第四節 java 字節流

1. I/O流概述

      大部分程序都需要進行輸入/輸出處理,比如從鍵盤讀取數據、從屏幕中輸出數據、從文件中寫數據等等。在 Java 中,把這些不同類型的輸入、輸出源抽象爲流(Stream),而其中輸入或輸出的數據則稱爲數據流(Data Stream),用統一的接口表示,從而使程序設計簡單明瞭。

 流是一組有順序的,有起點和終點的字節集合,是對數據傳輸的總稱或抽象。即數據在兩設備間的傳輸稱爲流,流的本質是數據傳輸,根據數據傳輸特性將流抽象爲各種類,方便更直觀的進行數據操作。

      流一般分爲輸入流(Input Stream)和輸出流(Output Stream)兩類,但這種劃分並不是絕對的。比如一個文件,當向其中寫數據時,它就是一個輸出流;當從其中讀取數據時,它就是一個輸入流。當然,鍵盤只是一個輸入流,而屏幕則只是一個輸出流。(其實我們可以通過一個非常簡單的方法來判斷,只要是向內存中寫入就是輸入流,從內存中寫出就是輸出流)


2. 基類:InputStream 和 OutputStream

字節流主要操作byte類型數據,以byte數組爲準,java 中每一種字節流的基本功能依賴於基本類 InputStream 和 Outputstream,他們是抽象類,不能直接使用。字節流能處理所有類型的數據(如圖片、avi等)。

2.1 InputStream

InputStream 是所有表示位輸入流的父類,繼承它的子類要重新定義其中所定義的抽象方法。InputStream 是從裝置來源地讀取數據的抽象表示,例如 System 中的標準輸入流 in 對象就是一個 InputStream 類型的實例。

我們先來看看 InputStream 類的方法:

方法說明

read()throws IOException從輸入流中讀取數據的下一個字節(抽象方法)

skip(long n) throws IOException跳過和丟棄此輸入流中數據的 n 個字節

available()throws IOException返回流中可用字節數

mark(int readlimit)throws IOException在此輸入流中標記當前的位置

reset()throws IOException將此流重新定位到最後一次對此輸入流調用 mark 方法時的位置

markSupport()throws IOException測試此輸入流是否支持 mark 和 reset 方法

close()throws IOException關閉流

在 InputStream 類中,方法 read() 提供了三種從流中讀數據的方法:

int read():從輸入流中讀一個字節,形成一個0~255之間的整數返回(是一個抽象方法)

int read(byte b[]):從輸入流中讀取一定數量的字節,並將其存儲在緩衝區數組 b 中。

int read(byte b[],int off,int len):從輸入流中讀取長度爲 len 的數據,寫入數組 b 中從索引 off 開始的位置,並返回讀取得字節數。

注意:對於這三個方法,若返回-1,表明流結束,否則,返回實際讀取的字符數。

2.2 OutputStream

OutputStream 是所有表示位輸出流的類之父類。子類要重新定義其中所定義的抽象方法,OutputStream 是用於將數據寫入目的地的抽象表示。例如 System 中的標準輸出流對象 out 其類型是java.io.PrintStream,這個類是 OutputStream 的子類。

OutputStream類方法:

方法說明

write(int b)throws IOException將指定的字節寫入此輸出流(抽象方法)

write(byte b[])throws IOException將字節數組中的數據輸出到流中

write(byte b[], int off, int len)throws IOException將指定 byte 數組中從偏移量 off 開始的 len 個字節寫入此輸出流

flush()throws IOException刷新此輸出流並強制寫出所有緩衝的輸出字節

close()throws IOException關閉流

例子:

結果:

一般來說,很少直接實現 InputStream 或 OutputStream 上的方法,因爲這些方法比較低級,通常會實現它們的子類。

3. 文件流

在 I/O 處理中,最常見的就是對文件的操作。java.io 包中所提供的文件操作類包括:

用於讀寫本地文件系統中的文件:FileInputStream 和 FileOutputStream

描述本地文件系統中的文件或目錄:File、FileDescriptor 和 FilenameFilter

提供對本地文件系統中文件的隨機訪問支持:RandomAccessFile

今天我們來學習文件流的 FileInputStream 和 FileOutputStream 。

FileInputStream 類用於打開一個輸入文件,若要打開的文件不存在,則會產生異常 FileNotFoundException,這是一個非運行時異常,必須捕獲或聲明拋棄;

FileOutputStream 類用來打開一個輸出文件,若要打開的文件不存在,則會創建一個新的文件,否則原文件的內容會被新寫入的內容所覆蓋;

在進行文件的讀/寫操作時,會產生非運行時異常 IOException,必須捕獲或聲明拋棄(其他的輸入/輸出流處理時也同樣需要進行輸入/輸出異常處理)。

文件流的構造方法:

例子:

輸入流的參數是用於指定輸入的文件名,輸出流的參數則是用於指定輸出的文件名。

4 .緩衝流

      類 BufferedInputStream 和 BufferedOutputStream 實現了帶緩衝的過濾流,它提供了緩衝機制,把任意的 I/O 流“捆綁”到緩衝流上,可以提高 I/O 流的讀取效率。

在初始化時,除了要指定所連接的 I/O 流之外,還可以指定緩衝區的大小。缺省時是用32字節大小的緩衝區;最優的緩衝區大小常依賴於主機操作系統、可使用的內存空間以及機器的配置等;一般緩衝區的大小爲內存頁或磁盤塊等的整數倍。

BufferedInputStream 的數據成員 buf 是一個位數組,默認爲2048字節。當讀取數據來源時例如文件,BufferedInputStream 會盡量將 buf 填滿。當使用 read ()方法時,實際上是先讀取 buf 中的數據,而不是直接對數據來源作讀取。當 buf 中的數據不足時,BufferedInputStream 纔會再實現給定的 InputStream 對象的 read() 方法,從指定的裝置中提取數據。

BufferedOutputStream 的數據成員 buf 是一個位數組,默認爲512字節。當使用 write() 方法寫入數據時,實際上會先將數據寫至 buf 中,當 buf 已滿時纔會實現給定的 OutputStream 對象的 write() 方法,將 buf 數據寫至目的地,而不是每次都對目的地作寫入的動作。

構造方法:

舉個例子,將緩衝流與文件流相接:

對於 BufferedOutputStream,只有緩衝區滿時,纔會將數據真正送到輸出流,但可以使用 flush() 方法人爲地將尚未填滿的緩衝區中的數據送出。

例如方法 copy():

5 .數據流

接口 DataInput 和 DataOutput,設計了一種較爲高級的數據輸入輸出方式:除了可處理字節和字節數組外,還可以處理 int、float、boolean等基本數據類型,這些數據在文件中的表示方式和它們在內存中的一樣,無須轉換,如 read(), readInt(), readByte()...; write(), writeChar(), writeBoolean()...此外,還可以用 readLine()方法讀取一行信息。

方法:

方法返回值說明

readBoolean()boolean

readByte()byte

readShort()short

readChar()char

readInt()int

readLong()long

readDouble()double

readFloat()float

readUnsignedByte()int

readUnsignedShort()int

readFully(byte[] b)void從輸入流中讀取一些字節,並將它們存儲在緩衝區數組 b 中

reaFully(byte[] b, int off,int len)void從輸入流中讀取 len 個字節

skipBytes(int n)int與 InputStream.skip 等價

readUTF()String安裝 UTF-8 形式從輸入中讀取字符串

readLine()String按回車(\r)換行(\n)爲分割符讀取一行字符串,不完全支持 UNICODE

writeBoolean(boolean v)void

writeByte(int v)void

writeShort(int v)void

writeChar(int v)void

writeInt(int v)void

writeLong(long v)void

writeFloat(float v)void

writeDouble(double v)void

write(byte[] b)void與 OutputStream.write 同義

write(byte[] b, int off, int len)void與OutputStream.write 同義

write(int b)void與OutputStream.write 同義

writeBytes(String s)void只輸出每個字符的低8位;不完全支持 UNICODE

writeChars(String s)void每個字符在輸出中都佔兩個字節

數據流類 DateInputStream 和 DataOutputStream 的處理對象除了是字節或字節數組外,還可以實現對文件的不同數據類型的讀寫:

分別實現了 DataInput 和 DataOutput 接口

在提供字節流的讀寫手段同時,以統一的形式向輸入流中寫入 boolean,int,long,double 等基本數據類型,並可以再次把基本數據類型的值讀取回來。

提供了字符串讀寫的手段

數據流可以連接一個已經建立好的數據對象,例如網絡連接、文件等。數據流可以通過如下方式建立:

接下來我們通過具體的代碼,看一看它的用法吧:

6.標準流、內存讀寫流、順序輸入流

2.6.1 標準流

語言包 java.lang 中的 System 類管理標準輸入/輸出流和錯誤流。

System.in從 InputStream 中繼承而來,用於從標準輸入設備中獲取輸入數據(通常是鍵盤)。

System.out從 PrintStream 中繼承而來,把輸入送到缺省的顯示設備(通常是顯示器)

System.err也是從 PrintStream 中繼承而來,把錯誤信息送到缺省的顯示設備(通常是顯示器)

每當 main 方法被執行時,就會自動生產上述三個對象。這裏就不再寫代碼驗證了。

6.2內存讀寫流

爲了支持在內存上的 I/O,java.io 中提供了類:ByteArrayInputStream、ByteArrayOutputStream 和 StringBufferInputStream

ByteArrayInputStream 可以從指定的字節數組中讀取數據

ByteArrayOutputStream 中提供了緩衝區可以存放數據(緩衝區大小可以在構造方法中設定,缺省爲32),可以用 write() 方法向其中寫入數據,然後用 toByteArray() 方法將緩衝區中的有效字節寫到字節數組中去。size() 方法可以知道寫入的字節數;reset() 可以丟棄所有內容。

StringBufferInputStream 與 ByteArrayInputStream 相類似,不同點在於它是從字符緩衝區 StringBuffer 中讀取16位的 Unicode 數據,而不是8位的字節數據(已被 StringReader 取代)

這裏只做簡要的介紹,有興趣的同學可以查看一下這些類裏具體的方法。

6.3 順序輸入流

java.io 中提供了類 SequenceInputStream,使應用程序可以將幾個輸入流順序連接起來。順序輸入流提供了將多個不同的輸入流統一爲一個輸入流的功能,這使得程序可能變得更加簡潔。

例如:



歡迎關注微信公衆號:Java的學習之路

裏面資料非常全,從java初級到高級都有,視頻,電子書,面試寶典,簡歷模板,經典案例,源碼分析程序員故事以及解決bug方法。。。。應有盡有,可以推薦大家一起學習下!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章