Java I/O是Java中很重要的組成部分
一.以字節(jié)為向?qū)У腟tream InputStream/OutputStream
Java I/O最基本的概念就是輸入流與輸出流逢并,即InputStream(輸入流)和OutputStream(輸出流)
InputStream
最基本的字節(jié)輸入流筒狠,抽象類,定義了讀取原始字節(jié)的所有基本方法
- read() 讀取一個(gè)字節(jié)的方法
- close() 關(guān)閉stream方法雇庙,這個(gè)是每次在用完流之后必須調(diào)用的方法灶伊。
- available() 返回stream中的可讀字節(jié)數(shù),inputstream類中的這個(gè)方法始終返回的是0聘萨,這個(gè)方法需要子類去實(shí)現(xiàn)米辐。
- skip(long n) 從stream中跳過long類型參數(shù)個(gè)位置
- read(byte b[]) 一次性讀取內(nèi)容到緩沖字節(jié)數(shù)組
- read(byte b[],int off,int len) 從數(shù)據(jù)流中的哪個(gè)位置offset開始讀長(zhǎng)度為len的內(nèi)容到緩沖字節(jié)數(shù)組
下面還有三個(gè)方法:
- mark(int readlimit) 用于標(biāo)記stream的作用
- markSupported() 返回的是boolean類型翘贮,因?yàn)椴皇撬械膕tream都可以調(diào)用mark方法的,這個(gè)方法就是用來判斷stream是否可以調(diào)用mark方法和reset方法
- reset() 這個(gè)方法和mark方法一起使用的锨能,讓stream回到mark的位置。
OutputStream
最基本的字節(jié)輸出流熄阻,抽象類倔约,定義了讀取原始字節(jié)的所有基本方法
- write(int b) 寫入一個(gè)字節(jié)到stream中
- close() 關(guān)閉流,這個(gè)是在操作完stream之后必須要調(diào)用的方法
- flush() 這個(gè)方法是用來刷新stream中的數(shù)據(jù)复濒,讓緩沖區(qū)中的數(shù)據(jù)強(qiáng)制的輸出
- write(byte b[]) 寫入一個(gè)byte數(shù)組到stream中
- write(byte b[], int off, int len) 把byte數(shù)組中從offset開始處寫入長(zhǎng)度為len的數(shù)據(jù)
總結(jié)
InputStream和OutputStream定義了I/O領(lǐng)域最基礎(chǔ)的行為乒省,也就是讀取和寫入一個(gè)字節(jié),同時(shí)使用了模板方法將讀取和寫入的行為進(jìn)行了適當(dāng)擴(kuò)展袖扛。
擴(kuò)展一:對(duì)I/O流的繼承
InputStream和OutputStream都是抽象類蛆封,它們僅僅定義了I/O領(lǐng)域最基礎(chǔ)的方法,但不涉及具體實(shí)現(xiàn)惨篱。針對(duì)不同的數(shù)據(jù)來源砸讳,InputStream和OutputStream存在三種實(shí)現(xiàn):一種是基于內(nèi)存的ByteArrayInputStream/ByteArrayOutputStream,一種是基于磁盤文件的FileInputStream/FileOutputStream簿寂,還有一種是基于網(wǎng)絡(luò)的SocketInputStream/SocketOutputStream。
FileInputStream/FileOutputStream
讀取寫入的源是操作系統(tǒng)的文件使用native方法進(jìn)行底層文件的讀取
try
{
//使用FileInputStream和FileOutputStream進(jìn)行文件復(fù)制
FileInputStream fis=new FileInputStream("a.txt");
FileOutputStream fos=new FileOutputStream("b.txt");
int read;
//read=fis.read();
byte b[]=new byte[1024];
//讀取文件纳令,存入字節(jié)數(shù)組b克胳,返回讀取到的字符數(shù),存入read,默認(rèn)每次將b數(shù)組裝滿
read=fis.read(b);
while(read!=-1)
{
fos.write(b,0,read);
read=fis.read(b);
//read=fis.read();
}
fis.close();
fos.close();
}
catch (IOException e)
{
e.printStackTrace();
}
ByteArrayInputStream/ByteArrayOutputStream
讀取寫入的源是內(nèi)存的一個(gè)數(shù)組捏雌,比較少見
SocketInputStream/SocketOutputStream
讀取寫入遠(yuǎn)程服務(wù)器的數(shù)據(jù)流使用native方法進(jìn)行底層文件的讀取
除上述3種以外還有別的實(shí)現(xiàn)如下
StringBufferInputStream/StringBufferOutputStream
據(jù)指定串創(chuàng)建一個(gè)讀取數(shù)據(jù)的輸入流串
PipedInputStream/PipedOutputStream
實(shí)現(xiàn)了pipe的概念腹忽,主要在線程中使用砚作,管道輸入流是指一個(gè)通訊管道的接收端。
一個(gè)線程通過管道輸出流發(fā)送數(shù)據(jù)葫录,而另一個(gè)線程通過管道輸入流讀取數(shù)據(jù)米同,這樣可實(shí)現(xiàn)兩個(gè)線程間的通訊。
SequenceInputStream/SequenceOutputStream
把多個(gè)In(Out)putStream合并為一個(gè)In(Out)putStream面粮,“序列輸入(出)流”類允許應(yīng)用程序把幾個(gè)輸入(出)流連續(xù)地合并起來,
并且使它們像單個(gè)輸入(出)流一樣出現(xiàn)稍走。每個(gè)輸入(出)流依次被讀取柴底,直到到達(dá)該流的末尾。
然后“序列輸入(出)流”類關(guān)閉這個(gè)流并自動(dòng)地切換到下一個(gè)輸入(出)流狐树。
擴(kuò)展二:對(duì)I/O流的擴(kuò)展
FilterInputStream/FilterOutputStream
FilterInputStream是InputStream一個(gè)特殊的子類鸿脓,它內(nèi)部有一個(gè)很重要的變量如下
protected volatile InputStream in;
protected FilterInputStream(InputStream in) {
this.in = in;
}
這說明了FilterInputStream在實(shí)例化的時(shí)候,要傳一個(gè)InputStream類的對(duì)象進(jìn)來味赃。
這個(gè)類的特殊之處虐拓,就是包含了一個(gè)InputStream,使得可以在這個(gè)InputStream基礎(chǔ)上進(jìn)行多種封裝城榛,從而達(dá)到裝飾的目的态兴。
這個(gè)類本身作用不大,但是他的子類比較有作用
DataInputStream/DataOutputStream
這兩個(gè)類繼承了FilterInputStream/FilterOutputStream瞻润,用來實(shí)現(xiàn)將java基本類型轉(zhuǎn)換成二進(jìn)制來進(jìn)行讀寫操作,readInt,readFloat,readDouble...這樣可以直接從stream中讀取基本類型的數(shù)據(jù)
BufferedInputStream/BufferedOutputStream
繼承了FilterInputStream正勒,實(shí)現(xiàn)了輸入流處理中的緩沖的功能。底層的流會(huì)先被讀取到一個(gè)字節(jié)數(shù)組中祥绞,用戶使用BufferedInputStream讀取數(shù)據(jù)的時(shí)候鸭限,會(huì)先讀取字節(jié)數(shù)組中的數(shù)據(jù),讀完了才會(huì)調(diào)用底層的流進(jìn)行進(jìn)一步的讀取兜喻。這種方法可以提升讀取的性能赡麦。繼承了FilterOutputStream,實(shí)現(xiàn)了輸出流處理中的緩沖功能车荔。當(dāng)用戶寫入數(shù)據(jù)的時(shí)候戚扳,其實(shí)是先寫入到BufferedOutputStream的一個(gè)字節(jié)數(shù)組中,當(dāng)這個(gè)字節(jié)數(shù)組滿了珠增,才會(huì)真正調(diào)用底層的輸出流執(zhí)行輸出動(dòng)作砍艾。這種方法可以提升寫入的性能。在使用BufferedOutputStream的寫入功能時(shí)脆荷,一定要使用flush蜓谋,因?yàn)榫彌_數(shù)組不滿的時(shí)候是不會(huì)寫入底層流的,在寫入最后一點(diǎn)數(shù)據(jù)的時(shí)候桃焕,緩沖數(shù)據(jù)不一定被填滿观堂,這時(shí)候就需要調(diào)用flush進(jìn)行強(qiáng)制刷新呀忧。
PrintStream
繼承FilterOutputStream溃睹,這個(gè)類的print和println方法可以把java的一些基本類型數(shù)據(jù)轉(zhuǎn)換成字節(jié)寫入到底層輸出流,但是PrintStream對(duì)String的轉(zhuǎn)換是平臺(tái)相關(guān)的,不同的平臺(tái)會(huì)有不同的編碼腕铸,所以寫入到底層的字節(jié)也不同,因此PrintStream只適合于測(cè)試輸出虽界,不適合于一般的I/O操作涛菠,特別是網(wǎng)絡(luò)流。
PushbackInputStream
繼承了FilterInputStream礁叔,提供了一種回退的機(jī)制迄薄,可以實(shí)現(xiàn)unread,本質(zhì)是使用緩沖數(shù)組實(shí)現(xiàn)了涣易,也就是說冶伞,回退的范圍是有限的。
二.以字符為向?qū)У腟tream Reader/Writer
InputStream和OutputStream是面向字節(jié)的徒爹,而人類的習(xí)慣是面向字符芋类,因此InputStream和OutputStream對(duì)于程序猿的用戶體驗(yàn)不是太好,于是就需要提供一些面向字符的流榛瓮。由于DataInputStream/DataOutputStream在跨平臺(tái)的情況下存在問題巫击,因此精续,java設(shè)計(jì)者干脆仿照InputStream和OutputStream重新設(shè)計(jì)了一套面向字符的I/O粹懒,也就是Reader/Writer
Reader
基本的字符輸入流,是個(gè)抽象類
方法與InputStream對(duì)應(yīng)
Writer
基本的字符輸出流确垫,是個(gè)抽象類
方法與OutputStream對(duì)應(yīng)
擴(kuò)展一:對(duì)I/O流的繼承
CharArrayReader/CharArrayWriter
與前面ByteArrayInputStream/ByteArrayOutputStream對(duì)應(yīng)
StringReader/StringWriter
與前面StringBufferInputStream/StringBufferOutputStream對(duì)應(yīng)
FileReader/FileWriter
與前面FileInputStream/FileOutputStream對(duì)應(yīng)
PipedReader/PipedWriter
與前面PipedInputStream/PipedOutputStream對(duì)應(yīng)
擴(kuò)展二:對(duì)I/O流的擴(kuò)展
FilterReader/FilterWriter
BufferedReader/BufferedWriter
PushbackReader
PrintWriter
三.兩種不同導(dǎo)向的Stream之間的轉(zhuǎn)換
由于計(jì)算機(jī)只識(shí)別字節(jié)帽芽,所以Reader/Writer的數(shù)據(jù)來源最終還是字節(jié)导街,而他們無法直接和字節(jié)打交道,這時(shí)候就需要一個(gè)中介者將Reader/Writer和InputStream和OutputStream進(jìn)行打通搬瑰,于是就有了InputStreamReader和OutputStreamWriter
InputStreamReader 類是從字節(jié)流到字符流的橋梁:它讀入字節(jié)泽论,并根據(jù)指定的編碼方式,將之轉(zhuǎn)換為字符流。
使用的編碼方式可能由名稱指定佳晶,或平臺(tái)可接受的缺省編碼方式潮瓶。
InputStreamReader 的 read() 方法之一的每次調(diào)用毯辅,可能促使從基本字節(jié)輸入流中讀取一個(gè)或多個(gè)字節(jié)煞额。
為了達(dá)到更高效率,考慮用 BufferedReader 封裝 InputStreamReader 胀莹,
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
![](/Users/admin/Documents/Life/I:O/3400180-bce9503f7c9ee657.png =500x300)