Java IO流 -- 02 輸入輸出流

1.流的分類

(1)輸入輸出流
輸入輸出是針對程序運行的內(nèi)存而言的
輸入流的基類:InputStream,Reader
輸出流的基類:OutputStream, Write

(2)字節(jié)流和字符流
用法幾乎一樣,只是字節(jié)流和字符流所操作的數(shù)據(jù)單元不同,字節(jié)流操作的數(shù)據(jù)單元是8位的 字節(jié),而字符流操作的數(shù)據(jù)單位是16為 字符

字節(jié)流和字符流的處理方式很像,最大的區(qū)別只是處理的單位數(shù)據(jù)量不同

注:一個字符(char)是2個字節(jié),一個字節(jié)是8位.

(3)節(jié)點流和處理流
節(jié)點流是程序直接到實際的數(shù)據(jù)源進行讀寫操作,節(jié)點流又被稱為低級流,如FileInputStream,ByteArrayInputStream

處理流是用一個已存在的流(即節(jié)點流?)進行連接或封裝,程序通過該封裝的流來個實際數(shù)據(jù)源進行讀寫操作,換言之,程序不和實際的數(shù)據(jù)源直接連接。這樣可以增強代碼的通用性,

注: 1.java中用處理流包裝節(jié)點流是一種典型的裝飾器設計模式,這樣通過使用處理流來包裝不同的節(jié)點流,既可以消除不同節(jié)點流的實現(xiàn)差異(即代碼編寫的差異),也可以提供更方便的方法來完成輸入輸出功能,因此處理流也被稱為包裝流

2.數(shù)據(jù)源可能是磁盤、硬盤、網(wǎng)絡等,而不同的數(shù)據(jù)源,其代碼的編寫是有差異的,如果將這些節(jié)點流包裝成處理流,就可以使用相同的輸入輸出代碼來讀寫不同設備的數(shù)據(jù)。

3.處理流的優(yōu)點: (1)性能提高: 主要以增加緩沖的方式來提高輸入/輸出的效率;(2)操作便捷: 可以大批量的處理數(shù)據(jù)。

處理可以 嫁接 到任何已存在的流的基礎之上,這樣就可以是的Java應用程序采用相同的代碼,透明的方式來訪問不同的輸入輸出設備的數(shù)據(jù)流。

2.字節(jié)流和字符流

字節(jié)流操作的數(shù)數(shù)據(jù)單元是 字節(jié)
字符流操作的數(shù)據(jù)單元是 字符(2個字節(jié))

(1)InputStream和Reader
InputStream和Reader是所有輸入流的抽象基類,是所有輸入流的模板。
InputStream里包含的方法:
int read(); //一次從輸入流中讀取單個字節(jié)的數(shù)據(jù),返回所讀取的字節(jié)數(shù)據(jù)(已轉(zhuǎn)換為int類型了)
int read(byte[] b); //一次最多讀取b.length個字節(jié)的數(shù)據(jù),并將其存儲在byte數(shù)組中,并返回實際讀取的字節(jié)個數(shù)。這個byte[]就相當于一個取水的竹筒,用他去取水,當然這個竹筒里會有水了啊,并且當水源不夠的時候這個竹筒并不能裝滿。方法返回這個竹筒里實際裝的水量
int read(byte[] b, int off, int len); //讀取len個字節(jié)數(shù)據(jù),并將這些數(shù)據(jù)存儲在byte數(shù)組b中,但是放入的時候是從數(shù)組的off位置開始放入的,方法返回實際讀取到的字節(jié)數(shù)
long skip(long n);//跳過并丟棄該輸入流中的n字節(jié)數(shù)據(jù)后,才準備開始寫入數(shù)據(jù)
void close(); //關(guān)閉IO資源

Reader里的方法
int read(); //一次從輸入流中讀取單個字符返回所讀取的字符數(shù)據(jù)(已轉(zhuǎn)換為了int類型了)
int read(char[] cbuf); //一次最多讀取cbuf.length個字符的數(shù)據(jù),將讀取到的數(shù)據(jù)存儲到char數(shù)組中,并返回實際讀取到的字符個數(shù)
int read(char[] cbuf, int off, int len); //最多讀取len個字符數(shù)據(jù),并將讀取到的數(shù)據(jù)存儲到char數(shù)組中,從off位置開始存儲,返回實際讀取到的字符個數(shù)
void close(); //關(guān)閉IO資源

注:1.上面的read(Xxx[] b)方法返回-1時,表明數(shù)據(jù)已經(jīng)取完了
2.當沒有數(shù)據(jù)的時候,read()也會返回-1
3.直接將byte[]和char[]數(shù)組轉(zhuǎn)換為字符串
byte[] -> public String(byte[] bytes, int index, int length);
char[] -> public String(char[] chs, int index, int length);
4.注意數(shù)組長度的選取,如果太短,容易造成讀取中文字符(2個字節(jié))時出現(xiàn)亂碼
5.用完IO流后應該關(guān)閉其資源,因為這些IO資源不屬于內(nèi)存里的,故垃圾回收機制無法回收這些資源,因此需要手動關(guān)閉。Java7以后增加了自動關(guān)閉IO資源的機制,即只要處于try塊中的IO流在使用完畢后會自動關(guān)閉

(2)OutputStream和Write
OutputStream和Write是所有輸出流的抽象基類,是所有輸出流的模板。二者的用法完全一樣
OutputStream的方法
void write(int b); //將指定的字節(jié)(這里以int類型的形式表示該字節(jié))輸出到輸出流中。
void write(byte[] b); //將一組字節(jié)輸出到輸出流中
void write(byte[] b, int off, int len); //將一組字節(jié)從off位置開始,長度為len的字節(jié)輸出到輸出流中
void close()
void flush()

Write的方法
void write(int c); //將指定的字符(這里以int類型的形式表示該字符)輸出到輸出流中。
void write(char[] cbuf);
void write(char[] cbuf, int off, int len)
abstract void close(); //執(zhí)行這個方法前,系統(tǒng)會自動執(zhí)行flush()方法,
abstract void flush(); //刷新緩沖區(qū),將緩沖區(qū)中的數(shù)據(jù)刷新到物理節(jié)點中。

//因為字符流直接以字符作為操作單位,所以可以使用字符串來替代字符數(shù)組,因此,多了下面兩個方法
void write(String str)
void write(String str, int off, int len)

注意:
1.使用完輸出流后,切記一定要將IO流資源關(guān)閉,不僅可以保正資源被回收外,更重要的是可以將輸出緩沖區(qū)的數(shù)據(jù)flush到物理結(jié)點中。
2.輸出換行符時,不同的平臺不一樣,如Windows是\r\n, 而在UNIX/LINUX中\(zhòng)n

3.輸入輸出體系

節(jié)點流(如FileInputStream, FileOutputStream)使用起來很繁瑣,因此為了簡化程序的編寫,包裝出了處理流。

使用處理流的典型思路:使用處理流來包裝節(jié)點流,讓程序通過處理流來執(zhí)行輸入輸出的功能,而節(jié)點流只需負責與底層的I/O設備、文件交互。

從名稱上來識別處理流和節(jié)點流:只要流的構(gòu)造器參數(shù)不是一個物理節(jié)點(如stringPath, File等),而是一個已經(jīng)存在的流(如OutputStream),那么該流就一定是處理流,而所有的節(jié)點流的構(gòu)造器都是以物理IO節(jié)點作為參數(shù)。

使用處理流很簡單,只需給該處理流傳入一個節(jié)點流作為構(gòu)造器參數(shù)即可,這樣創(chuàng)建的處理流就是包裝了該節(jié)點流的處理流。

注意:
1.使用處理流時,只需關(guān)閉最上層的處理流即可,底層的節(jié)點流會自動關(guān)閉
2.如果輸出輸入的內(nèi)容是文本時,應該采用字符流(更高效),如果進行輸入輸出是二進制內(nèi)容時,則應該采使用字節(jié)流
3.Windows下簡體中文默認的使用GBK字符集,Linux下默認是UTF-8字符集

4.幾個重要的輸入輸出流
(1)FileInputStream和FileOutputStream、FileReader和FileWrite

前面講過

(2)BufferedInputStream和BufferedOutputStream、BufferedReader和BufferedWriter

BufferedInputStream
BufferedInputStream(InputStream in);
BufferedInputStream(InputStream in, int size)
int read()
int read(byte[] b, int off, int len)

BufferedOutputStream
BufferedOutputStream(OutputStream out);
BufferedOutputStream(OutputStream out, int size)
void write(byte[] b, int off, int len)
void write(int b)

BufferedReader
BufferedReader(Reader in);
BufferedReader(Reader in, int sz)
int read();
int read(char[] cbuf, int off, int len)
String readLine(); //一次讀取一行,沒有數(shù)據(jù)可讀時會返回null

例子

BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(a.java)));
String line;
while(line = br.readLine() != null) {
    System.out.println(line);
}

BufferedWriter
BufferedWriter(Writer out);
BufferedWriter(Writer out, int sz)
void write(char[] cbuf, int off, int len)
void write(int c)
void write(String s, int off, int len)
void newLine(); //根據(jù)系統(tǒng)來決定換行符
void close()
void flush()

注意:這種處理流體現(xiàn)的是一種裝飾器設計模式

(3)InputStreamReader和OutputStreamWrite

將字節(jié)流轉(zhuǎn)換為字符流
InputStreamReader
InputStreamReader(InputStream in); //
InputStreamReader(InputStream in, Charset cs); //指定字符集
InputStreamReader(InputStream in, CharsetDecoder dec)
InputStreamReader(InputStream in, String charsetName)
int read()
int read(char[] cbuf, int offset, int length)

OutputStreamWrite
OutputStreamWriter(OutputStream out);
OutputStreamWriter(OutputStream out, Charset cs);
OutputStreamWriter(OutputStream out, CharsetEncoder enc);
OutputStreamWriter(OutputStream out, String charsetName)
void write(char[] cbuf, int off, int len);
void write(int c);
void write(String str, int off, int len);
void close();
void flush();

注意:這兩個轉(zhuǎn)換流也是一種處理流,體現(xiàn)的是一種適配器模式

(4)PrintStream和PrintWrite

打印流,即輸出流
PrintStream
PrintStream(File file)
PrintStream(OutputStream out)
PrintStream(OutputStream out, boolean autoFlush);

PrintWrite
PrintWriter(File file);
PrintWriter(OutputStream out);
PrintWriter(OutputStream out, boolean autoFlush);

PrintStream的輸出功能非常強大,通常如果需要輸出文本內(nèi)容,都應該考慮將輸出流包裝成PrintStream后進行輸出

注:1.常常在處理文本文件時,將InputStream轉(zhuǎn)換為Reader,再進一步包裝成BufferedReader。
2.將OutputStream轉(zhuǎn)換為Write,再進一步包裝成BufferedWrite。
3.Scanner sc = new Scanner(System.in); System.in的本質(zhì)是InputStream 轉(zhuǎn)換為 ->
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str = br.readLine();

4.RandomAccessFile(隨機訪問文件流)

可以自由訪問文件的任意地方,所以,如果是只需訪問文件部分內(nèi)容,而不是從頭讀到尾,則使用這個是更好的選擇。

注意:RandomAccessFile只能讀寫文件,不能讀取其他的IO節(jié)點

RandomAccessFile(File file, String mode); //mode是讀寫模式,'r','rw','rws','rwd'
RandomAccessFile(String name, String mode)
long getFilePointer(); //返回文件記錄指針的當前位置
void setLength(long newLength); //設定文件大小
void seek(long pos); //將文件的記錄指針定位到pos位置(是相對于開頭處的跳躍),是絕對位移
int skipBytes(int n);//跳過n個字節(jié)(是相對于當前位置的跳躍),是相對位移
讀寫方法同InputStream,OutputStream

5.對象序列化(Serialize)與反序列化(Deserialize)

對象序列話的目的是為了將對象保存在磁盤(持久存儲)或者在網(wǎng)絡中直接傳輸對象,

對象序列化是指將一個Java對象寫入IO流中,與此對應的是反序列化從IO流中恢復該Java對象

實現(xiàn)一個對象序列化,則該對象必須實現(xiàn)Serializable(或Externalizable接口)接口,這是個標記接口

利用ObjectOutputStream和ObjectInputStream來實現(xiàn)對象的序列化輸出和反序列化輸入

ObjectOutputStream(OutputStream out);
void writeObject(Object obj); //將對象序列化后寫入輸出流中

ObjectInputStream(InputStream in);
Object readObject(); //從輸入流中讀取對象, 注意類型轉(zhuǎn)換

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,363評論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,497評論 3 416
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,305評論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,962評論 1 311
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,727評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,193評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,257評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,411評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,945評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,777評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,978評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,519評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,216評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,642評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,878評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,657評論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,960評論 2 373

推薦閱讀更多精彩內(nèi)容