引言
對(duì)程序語(yǔ)言設(shè)計(jì)者來(lái)說(shuō)野舶,設(shè)計(jì)一個(gè)令人滿(mǎn)意的I/O(輸入輸出)系統(tǒng)峦耘,是件極艱巨的任務(wù)砌们,摘自《Thinking in Java 》
概述
JAVA程序通過(guò)流來(lái)完成輸入/輸出贩虾。流是生產(chǎn)或消費(fèi)信息的抽象催烘,流通過(guò)Java的輸入/輸出系統(tǒng)與物理設(shè)備連接。JAVA的I/O通過(guò)java.io包下的類(lèi)和接口來(lái)支持缎罢,主要是5個(gè)類(lèi)和一個(gè)接口伊群。
- File:用于文件或目錄的描述信息,例如生成新目錄策精,修改文件名舰始,刪除文件,判斷文件路徑等
- InputStream:抽象類(lèi)咽袜,所有輸入流的父類(lèi)丸卷,定義了所有輸入流具有的共同特征。
- OutputStream:抽象類(lèi)酬蹋,基于字節(jié)的輸出操作及老,所有輸出流的父類(lèi)抽莱,定義了輸出流具有的共同特征范抓。
- Reader:抽象類(lèi),基于字符的輸入類(lèi)食铐。
- Writer:抽象類(lèi)匕垫,基于字符的輸出類(lèi)。
- Serializable:將Java對(duì)象轉(zhuǎn)換成平臺(tái)無(wú)關(guān)的二進(jìn)制數(shù)據(jù)
- RandomAccessFile:包裝了一個(gè)隨機(jī)訪問(wèn)的文件虐呻,實(shí)現(xiàn)了DataInput/DataOutput接口象泵。
File類(lèi)
一個(gè)File類(lèi)的對(duì)象寞秃,表示了磁盤(pán)上的文件或目錄,提供了與平臺(tái)無(wú)關(guān)的方法來(lái)對(duì)磁盤(pán)上的文件或者目錄進(jìn)行操作偶惠,直接處理文件或目錄春寿,但是不能訪問(wèn)文件本身。
在java.io包中提供了60多了類(lèi)流:
從功能上分為:
- 輸入流:從外部流向內(nèi)存
- 輸出流:從內(nèi)存流向外部
從流的角色上分為:
- 節(jié)點(diǎn)流:可以從/向一個(gè)特定的IO設(shè)備(磁盤(pán)忽孽,網(wǎng)絡(luò))讀/寫(xiě)數(shù)據(jù)的流绑改,直接連接物理設(shè)備或socket
- 處理流:對(duì)一個(gè)已經(jīng)存在的流(節(jié)點(diǎn)流)進(jìn)行連接或者封裝。
從流的結(jié)構(gòu)上分為:
- 字節(jié)流 :InputStream OutputStream
- 字符流 : Reader Writer
在最底層兄一,所有的輸入輸出都是以字節(jié)為單位的厘线,基于字符的流只是為處理字符提供方便有效的方法。它們的操作方式幾乎完全一樣出革,只是操作的數(shù)據(jù)單元不同造壮,字節(jié)流操作的數(shù)據(jù)單元是字符,字符流操作的數(shù)據(jù)單元是字符骂束。
類(lèi)流全家福
從上面的圖片中耳璧,可以看出無(wú)論是字節(jié)流和字符流都提供了對(duì)文件,數(shù)組展箱,字符串楞抡,管道,對(duì)象析藕,音頻等內(nèi)容的輸入/輸出流支持召廷。
對(duì)輸入/輸出流基類(lèi)的簡(jiǎn)單介紹
InputSteam 三個(gè)基本的讀方法:
abstract int read(): 讀取一個(gè)字節(jié)數(shù)據(jù),并返回讀到數(shù)據(jù)的末尾账胧,如果返回-1 竞慢, 表示都到了輸入流的末尾。
int read(byte[] b ): 將數(shù)據(jù)讀入一個(gè)字節(jié)數(shù)組治泥,同時(shí)返回實(shí)際讀取的字節(jié)數(shù)筹煮,如果返回-1 ,表示讀到了輸入流的末尾居夹。
int read(byte[] b , int off , int len):將數(shù)據(jù)讀入一個(gè)字節(jié)數(shù)組败潦,同時(shí)返回實(shí)際讀取的字節(jié)數(shù),如果返回-1 准脂,表示讀到了輸入流的末尾劫扒,off指定在數(shù)組b中存放數(shù)據(jù)的起始位置,len指定讀取的最大字節(jié)數(shù)狸膏。
可能會(huì)有一個(gè)疑問(wèn)沟饥,為什么上面的第一個(gè)方法是抽象,而其余兩個(gè)read方法是具體的? 通過(guò)源碼找到了想要的答案。第二個(gè)方法依靠了第三個(gè)方法贤旷,而第三個(gè)方法依靠了第一個(gè)方法實(shí)現(xiàn)广料,換句話說(shuō)只有第一個(gè)read方法是與具體的I/O設(shè)備相關(guān)的,需要InputStream的子類(lèi)來(lái)實(shí)現(xiàn)幼驶。源碼如下:
public abstract int read() throws IOException;
public int read(byte b[]) throws IOException {
return read(b, 0, b.length); //調(diào)用第三個(gè)方法實(shí)現(xiàn)
}
public int read(byte b[], int off, int len) throws IOException {
//判斷參數(shù)的合法性
if (b == null) {
throw new NullPointerException();
} else if (off < 0 || len < 0 || len > b.length - off) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
int c = read(); //調(diào)用第一個(gè)方法艾杏,讀取一個(gè)字節(jié)
if (c == -1) {
return -1; //沒(méi)有字節(jié)返回-1 ,讀取結(jié)束
}
b[off] = (byte)c; //將讀取到的字節(jié)放入數(shù)組中
int i = 1;
try {
for (; i < len ; i++) {
c = read();
if (c == -1) {
break;
}
b[off + i] = (byte)c; //將讀取到的字節(jié)放入數(shù)組中盅藻,讀取的長(zhǎng)度大于數(shù)據(jù)長(zhǎng)度糜颠,循環(huán)讀取結(jié)束
}
} catch (IOException ee) {
}
return i; //返回讀取的字節(jié)數(shù)組長(zhǎng)度
}
其它方法
long skip(long n ):輸入流中跳過(guò)n個(gè)字節(jié),并返回實(shí)際跳過(guò)的字節(jié)數(shù)
void close():關(guān)閉流
萧求。其兴。。
OutputStream 主要方法
void write(byte[]] b ):將參數(shù)b中的字節(jié)寫(xiě)到輸出流
void write(byte[] b , int off ,int len):將參數(shù)b的從偏移量off開(kāi)始len個(gè)字節(jié)寫(xiě)到輸出流
abstract viud write(int b ):先將int轉(zhuǎn)換成byte類(lèi)型夸政,把低字節(jié)寫(xiě)入到輸出流中
void flush():將緩沖區(qū)中的字節(jié)全部輸出元旬,并清空緩存區(qū)
void close():關(guān)閉輸出流并釋放與流相關(guān)的系統(tǒng)資源
Reader里包含的3個(gè)讀取方法:
int read():
int read(char[] c):
int read(char[] c ,int off , int len) :
Write包含的方法
void write(char[] c)
void write(String str)
void write(String str, int off, int len)
abstract flush()
void close()
根據(jù)上面圖片做一個(gè)簡(jiǎn)單的總結(jié):
- FileInputStream和FileOutputStream 節(jié)點(diǎn)流,用于對(duì)文件讀取或往文件中寫(xiě)入字節(jié)流守问。如果在構(gòu)造FileOutputStream時(shí)匀归,文件已經(jīng)存在,則覆蓋整個(gè)文件耗帕。
- BufferedInputStream和BufferedOutputStream過(guò)濾流穆端,需要使用已經(jīng)存在的節(jié)點(diǎn)流來(lái)構(gòu)造,提供了讀寫(xiě)的效率仿便。
- DataInputStream和DataOutputStream 過(guò)濾流体啰,需要使用已經(jīng)存在的節(jié)點(diǎn)流來(lái)構(gòu)造,提供了讀寫(xiě)Java中基本數(shù)據(jù)類(lèi)型的功能嗽仪。
- PipedInputStream和PipedOutputStream 管道流荒勇,用于線程間的通信,一個(gè)線程的PipedInputStream對(duì)象從另一個(gè)線程的PipedOutputStream 對(duì)象讀取輸入闻坚,只要管道流有用沽翔,必須提供同時(shí)構(gòu)造管道輸入流和管道輸出流。
- InputStreamReader和OutputStreamWriter類(lèi)窿凤,用于處理字符流的基本類(lèi)仅偎,用來(lái)在字節(jié)流和字符流之間搭一座橋。將字節(jié)流和字符流進(jìn)行轉(zhuǎn)換雳殊。
- FileReader和FileWriter 可以創(chuàng)建一個(gè)可以讀/寫(xiě)文件的類(lèi)橘沥。
- BufferedReader:通過(guò)緩沖輸入提高性能。
- SequenceInputStream:把多個(gè)InputStream合并為一個(gè)InputStream
I/O流的鏈接示意圖:
常用類(lèi)
FileInputStream , FileOutputStream , ByteArrayInputStream, ByteArrayOutputStream 相种,BufferedReader,BufferedWriter, ,InputStreamReader ,InputStreamWriter威恼,F(xiàn)ileReader ,FileWriter
如何選擇I/O流
確定是輸入還是輸出
輸入:輸入流 InputStream Reader
輸出:輸出流 OutputStream Writer
明確操作的數(shù)據(jù)對(duì)象是否是純文本
是:字符流 Reader,Writer
否:字節(jié)流 InputStream寝并,OutputStream
明確具體的設(shè)備箫措。
文件:
讀:FileInputStream,, FileReader,
寫(xiě):FileOutputStream,F(xiàn)ileWriter
數(shù)組:
byte[ ]:ByteArrayInputStream, ByteArrayOutputStream
char[ ]:CharArrayReader, CharArrayWriter
String:
StringBufferInputStream(已過(guò)時(shí)衬潦,因?yàn)槠渲荒苡糜赟tring的每個(gè)字符都是8位的字符串), StringReader, StringWriter
Socket流
鍵盤(pán):用System.in(是一個(gè)InputStream對(duì)象)讀取斤蔓,用System.out(是一個(gè)OutoutStream對(duì)象)打印
是否需要轉(zhuǎn)換流
是,就使用轉(zhuǎn)換流镀岛,從Stream轉(zhuǎn)化為Reader弦牡、Writer:InputStreamReader,OutputStreamWriter
是否需要緩沖提高效率
是就加上Buffered:BufferedInputStream, BufferedOuputStream, BufferedReader, BufferedWrite
少年聽(tīng)雨歌樓上漂羊,紅燭昏羅帳驾锰。
壯年聽(tīng)雨客舟中,江闊云低走越,斷雁叫西風(fēng)椭豫。
感謝支持!
---起個(gè)名忒難