Java源码解析——Java IO包
一、基礎(chǔ)知識(shí):
1. Java IO一般包含兩個(gè)部分:1)java.io包中阻塞型IO;2)java.nio包中的非阻塞型IO,通常稱為New IO。這里只考慮到j(luò)ava.io包中堵塞型IO;
2. Java.io包簡(jiǎn)單地分類。
2.1 Java的IO主要包含三個(gè)部分:
1)流式部分――IO的主體部分;
2)非流式部分――主要包含一些輔助流式部分的類,如:File類、RandomAccessFile類和FileDescriptor等類;
3)文件讀取部分的與安全相關(guān)的類,如:SerializablePermission類。以及與本地操作系統(tǒng)相關(guān)的文件系統(tǒng)的類,如:FileSystem類和Win32FileSystem類和WinNTFileSystem類。
2.2 流式部分可以概括:
1)字節(jié)流(Byte Stream)和字符流(Char Stream)的對(duì)應(yīng);
2)輸入和輸出的對(duì)應(yīng)。
3)從字節(jié)流到字符流的橋梁。對(duì)應(yīng)于輸入和輸出為InputStreamReader和OutputStreamWriter。
2.3?流的具體類中又可以具體分為:
?????? 1)介質(zhì)流(Media Stream或者稱為原始流Raw Stream)――主要指一些基本的流,他們主要是從具體的介質(zhì)上,如:文件、內(nèi)存緩沖區(qū)(Byte數(shù)組、Char數(shù)組、StringBuffer對(duì)象)等,讀取數(shù)據(jù);
?????? 2)過濾流(Filter Stream)――主要指所有FilterInputStream/FilterOutputStream和FilterReader/FilterWriter的子類,主要是對(duì)其包裝的類進(jìn)行某些特定的處理,如:緩存等。
2.4?節(jié)點(diǎn)流和處理流
1)節(jié)點(diǎn)流是FileInputStream、ByteArrayInputStream這些直接從某個(gè)地方獲取流的類;
?????? 2)處理流則是BufferedInputStream這種可以裝飾節(jié)點(diǎn)流,來實(shí)現(xiàn)特定功能的類。因此,節(jié)點(diǎn)流可以理解為裝飾者模式中的被裝飾者,處理流則是裝飾者。
?
類圖可以參考博客:https://blog.csdn.net/u013063153/article/category/6399747
?
二、類的分析
?
1、輸入字節(jié)流
?
IO中輸入字節(jié)流的繼承圖:
-InputStream-ByteArrayInputStream //將內(nèi)存中的Byte數(shù)組適配為一個(gè)InputStream-FileInputStream //最基本的文件輸入流。主要用于從文件中讀取信息-FilterInputStream //給其它被裝飾對(duì)象提供額外功能的抽象類-BufferedInputStream //使用該對(duì)象阻止每次讀取一個(gè)字節(jié)都會(huì)頻繁操作IO。將字節(jié)讀取一個(gè)緩存區(qū),從緩存區(qū)讀取。-DataInputStream //使用它可以讀出基本數(shù)據(jù)類型-LineNumberInputStream //跟蹤輸入流中的行號(hào)。可以得到和設(shè)置行號(hào)。-PushbackInputStream //可以在讀取最后一個(gè)byte 后將其放回到緩存中。-ObjectInputStream-PipedInputStream //在流中實(shí)現(xiàn)了管道的概念讀取PipedOutputStream寫入的數(shù)據(jù)。-SequenceInputStream //將2個(gè)或者多個(gè)InputStream 對(duì)象轉(zhuǎn)變?yōu)橐粋€(gè)InputStream-StringBufferInputStream //將內(nèi)存中的字符串適配為一個(gè)InputStream(廢棄)1)InputStream是抽象類,是所有字節(jié)輸入流的超類。
2)ByteArrayInputStream、StringBufferInputStream、FileInputStream是三種基本的介質(zhì)流,它們分別將Byte數(shù)組、StringBuffer、和本地文件中讀取數(shù)據(jù)。PipedInputStream是從與其它線程共用的管道中讀取數(shù)據(jù);
3)ObjectInputStream和所有FilterInputStream的子類都是裝飾流(裝飾器模式的主角)。
4)FileInputStream 文件輸入流,用于讀取本地文件中的字節(jié)數(shù)據(jù)。
?
2. IO中的輸出字節(jié)流
?
?IO中輸出字節(jié)流的繼承圖:
-OutputStream-ByteArrayOutputStream //在內(nèi)存中創(chuàng)建一個(gè)buffer。所有寫入此流中的數(shù)據(jù)都被放入到此buffer中。-FileOutputStream //將信息寫入文件中。-FilterOutputStream //實(shí)現(xiàn)OutputStream裝飾器功能的抽象類。 -BufferedOutputStream //使用該對(duì)象阻止每次讀取一個(gè)字節(jié)都會(huì)頻繁操作IO。將字節(jié)讀取一個(gè)緩存區(qū),從緩存區(qū)讀取。-DataOutputStream //使用它可以寫入基本數(shù)據(jù)類型。 -PrintStream //產(chǎn)生具有格式的輸出信息。(一般地在java程序中DataOutputStream用于數(shù)據(jù)的存儲(chǔ),即J2EE中持久層完成的功能,PrintStream完成顯示的功能,類似于J2EE中表現(xiàn)層的功能)-BufferedOutputStream //使用它可以避免頻繁地向IO寫入數(shù)據(jù),數(shù)據(jù)一般都寫入一個(gè)緩存區(qū),在調(diào)用flush方法后會(huì)清空緩存、一次完成數(shù)據(jù)的寫入。 -PipedOutputStream //任何寫入此對(duì)象的信息都被放入對(duì)應(yīng)PipedInputStream 對(duì)象的緩存中,從而完成線程的通信,實(shí)現(xiàn)了“管道”的概念。1)OutputStream是所有的輸出字節(jié)流的父類,它是一個(gè)抽象類。
2)ByteArrayOutputStream、FileOutputStream是兩種基本的介質(zhì)流,它們分別向Byte數(shù)組、和本地文件中寫入數(shù)據(jù)。PipedOutputStream是向與其它線程共用的管道中寫入數(shù)據(jù)。
3)ObjectOutputStream和所有FilterOutputStream的子類都是裝飾流。
?
3.?字節(jié)流的輸入與輸出的對(duì)應(yīng)
1)LineNumberInputStream主要完成從流中讀取數(shù)據(jù)時(shí),會(huì)得到相應(yīng)的行號(hào),至于什么時(shí)候分行、在哪里分行是由改類主動(dòng)確定的,并不是在原始中有這樣一個(gè)行號(hào)。在輸出部分沒有對(duì)應(yīng)的部分,我們完全可以自己建立一個(gè)LineNumberOutputStream,在最初寫入時(shí)會(huì)有一個(gè)基準(zhǔn)的行號(hào),以后每次遇到換行時(shí)會(huì)在下一行添加一個(gè)行號(hào),看起來也是可以的。
2)PushbackInputStream的功能是查看最后一個(gè)字節(jié),不滿意就放入緩沖區(qū)。主要用在編譯器的語法、詞法分析部分。輸出部分的BufferedOutputStream幾乎實(shí)現(xiàn)相近的功能。
3)SequenceInputStream可以認(rèn)為是一個(gè)工具類,將兩個(gè)或者多個(gè)輸入流當(dāng)成一個(gè)輸入流依次讀取。完全可以從IO包中去除,還完全不影響IO包的結(jié)構(gòu),卻讓其更“純潔”――純潔的Decorator模式。
4)PrintStream也可以認(rèn)為是一個(gè)輔助工具。主要可以向其他輸出流,或者FileInputStream寫入數(shù)據(jù),本身內(nèi)部實(shí)現(xiàn)還是帶緩沖的。本質(zhì)上是對(duì)其它流的綜合運(yùn)用的一個(gè)工具而已。一樣可以踢出IO包!System.out和System.out就是PrintStream的實(shí)例!
5)ObjectInputStream/ObjectOutputStream和DataInputStream/DataOutputStream主要是要求寫對(duì)象/數(shù)據(jù)和讀對(duì)象/數(shù)據(jù)的次序要保持一致,否則輕則不能得到正確的數(shù)據(jù),重則拋出異常;
6)PipedInputStream/PipedOutputStream在創(chuàng)建時(shí)一般就一起創(chuàng)建,調(diào)用它們的讀寫方法時(shí)會(huì)檢查對(duì)方是否存在,或者關(guān)閉。
?
4. 輸入字符流
IO中輸入字符流的繼承圖:
-Reader-BufferedReader-LineNumberReader-CharArrayReader-FilterReader-PushbackReader-InputStreamReader-FileReader-PipedReader-StringReader1)Reader是所有的輸入字符流的父類,它是一個(gè)抽象類。
2)CharReader、StringReader是兩種基本的介質(zhì)流,它們分別將Char數(shù)組、String中讀取數(shù)據(jù)。PipedReader是從與其它線程共用的管道中讀取數(shù)據(jù)。
3)BufferedReader很明顯就是一個(gè)裝飾器,它和其子類負(fù)責(zé)裝飾其它Reader對(duì)象。
4)FilterReader是所有自定義具體裝飾流的父類,其子類PushbackReader對(duì)Reader對(duì)象進(jìn)行裝飾,會(huì)增加一個(gè)行號(hào)。
5)InputStreamReader是字節(jié)流向字符流轉(zhuǎn)化的橋梁,它使用指定的 charset 讀取字節(jié)并將其解碼為字符。它使用的字符集可以由名稱指定或顯式給定,或者可以接受平臺(tái)默認(rèn)的字符集。其構(gòu)造方法的默認(rèn)參數(shù)為InputStream 對(duì)象。
使用方法:
InputStreamReader(InputStream in),InputStreamReader(Inputstreamin, charset cs)
為了達(dá)到最高效率,InputStreamReader通常用法為:
BufferedReader in = new BufferedReader(newInputStreamReader(System.in));BufferedReader:緩沖輸入流,包裝其他字符輸入流,提高讀取效率,從字符輸入流中讀取文本,緩沖各個(gè)字符,從而實(shí)現(xiàn)字符、數(shù)組和行的高效讀取。Reader的讀取操作開銷大,為提高效率使用BufferedReader包裝其他Reader(如FileReader和InputStreamReader)
?
5.?輸出字符流:
IO中輸出字符流的繼承圖:
-Writer-BufferedWriter-CharArrayWriter-FilterWriter-OutputStreamWriter-FileWriter-PipedWriter-PrintWriter-StringWriter1)Writer是所有的輸出字符流的父類,它是一個(gè)抽象類。
2)CharArrayWriter、StringWriter是兩種基本的介質(zhì)流,它們分別向Char數(shù)組、String中寫入數(shù)據(jù)。PipedWriter是向與其它線程共用的管道中寫入數(shù)據(jù)。
3) BufferedWriter是一個(gè)裝飾器為Writer提供緩沖功能。
4)PrintWriter和PrintStream極其類似,功能和使用也非常相似。
5)OutputStreamWriter:是字符流通向字節(jié)流的橋梁,它使用指定的 charset 讀取字符并將其解碼為字節(jié)。它使用的字符集可以由名稱指定或顯式給定,或者可以接受平臺(tái)默認(rèn)的字符集。
使用方法:
其構(gòu)造方法的默認(rèn)參數(shù)為OutputStream 對(duì)象,
OutputStreamReader(InputStream in), OutputStreamReader(Inputstream in, charset cs)為了達(dá)到最高效率,OutputStreamReader通常用法為:
BufferedWriter out = new BufferedWriter(newOutputStreamWriter(System.in));BufferedWriter:緩沖輸出流,包裝其他字符輸出流,提高讀取效率,將文本寫入字符輸出流,緩沖各個(gè)字符,從而提供單個(gè)字符、數(shù)組和字符串的高效寫入Writer的讀取操作開銷大,為提高效率使用BufferedWriter包裝其他Writer(如FileWriter和InputStreamWriter)
?
6. 序列化與反序列化:ObjectInputStream,ObjectOutputStream
JAVA提出序列化是為了將對(duì)象在ObjectOutputStream:對(duì)象輸出流,它的writeObject(Object obj)方法可以對(duì)參數(shù)指定的obj對(duì)象進(jìn)行序列化,把得到的字節(jié)序列寫到一個(gè)目標(biāo)輸出流中。
序列化過程:
File file = new File(“path”); OutputStream fos = new FileOutputStream(file); ObjectOutputStream oos = new ObjectOutputStream(“fos”);將輸出流對(duì)象輸出到file對(duì)象中。 oos.writeObject(Object obj); oos.flush(); oos.close();ObjectInputStream:對(duì)象輸入流,它的readObject()方法可以序列化文件進(jìn)行反序列化,把字節(jié)序列文件轉(zhuǎn)化為對(duì)象。
反序列化過程:
File file = new File(“path”) InputStream fis = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(fis); Class obj = (class)ois.readObject(); Ois.close();實(shí)現(xiàn)序列化的兩種方式:
1)類實(shí)現(xiàn)Serializable接口,類只有實(shí)現(xiàn)了serializable接口,ObjectOutputstream才會(huì)去將類的對(duì)象序列化,否則會(huì)拋出NotSerializableException異常
2)類繼承Externalizable類。
?
三、主要源碼實(shí)現(xiàn):
1.InputStream:
public abstract class InputStream implements Closeable {private static final int SKIP_BUFFER_SIZE = 2048; //用于skip方法,和skipBuffer相關(guān)private static byte[] skipBuffer; // skipBuffer is initialized in skip(long), if needed.//從輸入流中讀取下一個(gè)字節(jié),//正常返回0-255,到達(dá)文件的末尾返回-1//在流中還有數(shù)據(jù),但是沒有讀到時(shí)該方法會(huì)阻塞(block)//Java IO和New IO的區(qū)別就是阻塞流和非阻塞流//抽象方法!不同的子類不同的實(shí)現(xiàn)!public abstract int read() throws IOException; //將流中的數(shù)據(jù)讀入放在byte數(shù)組的第off個(gè)位置先后的len個(gè)位置中//放回值為放入字節(jié)的個(gè)數(shù)。//這個(gè)方法在利用抽象方法read,某種意義上簡(jiǎn)單的Templete模式。public int read(byte b[], int off, int len) throws IOException {//檢查輸入是否正常。一般情況下,檢查輸入是方法設(shè)計(jì)的第一步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;} //讀取下一個(gè)字節(jié)int c = read();//到達(dá)文件的末端返回-1if (c == -1) { return -1; }//放回的字節(jié)downcast b[off] = (byte)c;//已經(jīng)讀取了一個(gè)字節(jié) int i = 1; try {//最多讀取len個(gè)字節(jié),所以要循環(huán)len次for (; i < len ; i++) {//每次循環(huán)從流中讀取一個(gè)字節(jié)//由于read方法阻塞,//所以read(byte[],int,int)也會(huì)阻塞c = read();//到達(dá)末尾,理所當(dāng)然放回-1 if (c == -1) { break; } //讀到就放入byte數(shù)組中b[off + i] = (byte)c;}} catch (IOException ee) { }return i;}//利用上面的方法read(byte[] b)public int read(byte b[]) throws IOException {return read(b, 0, b.length);} //方法內(nèi)部使用的、表示要跳過的字節(jié)數(shù)目,public long skip(long n) throws IOException {long remaining = n; int nr;if (skipBuffer == null)//初始化一個(gè)跳轉(zhuǎn)的緩存skipBuffer = new byte[SKIP_BUFFER_SIZE]; //本地化的跳轉(zhuǎn)緩存byte[] localSkipBuffer = skipBuffer; //檢查輸入?yún)?shù),應(yīng)該放在方法的開始 if (n <= 0) { return 0; } //一共要跳過n個(gè),每次跳過部分,循環(huán) while (remaining > 0) { nr = read(localSkipBuffer, 0, (int) Math.min(SKIP_BUFFER_SIZE, remaining));//利用上面的read(byte[],int,int)方法盡量讀取n個(gè)字節(jié) //讀到流的末端,則返回if (nr < 0) { break; }//沒有完全讀到需要的,則繼續(xù)循環(huán)remaining -= nr; } return n - remaining;//返回時(shí)要么全部讀完,要么因?yàn)榈竭_(dá)文件末端,讀取了部分 }//查詢流中還有多少可以讀取的字節(jié)//該方法不會(huì)block。在java中抽象類方法的實(shí)現(xiàn)一般有以下幾種方式://1.拋出異常(java.util);2.“弱”實(shí)現(xiàn)。像上面這種。子類在必要的時(shí)候覆蓋它。//3.“空”實(shí)現(xiàn)。public int available() throws IOException { return 0;}//關(guān)閉當(dāng)前流、同時(shí)釋放與此流相關(guān)的資源//關(guān)閉當(dāng)前流、同時(shí)釋放與此流相關(guān)的資源public void close() throws IOException {}//markSupport可以查詢當(dāng)前流是否支持markpublic synchronized void mark(int readlimit) {}//對(duì)mark過的流進(jìn)行復(fù)位。只有當(dāng)流支持mark時(shí)才可以使用此方法。public synchronized void reset() throws IOException {throw new IOException("mark/reset not supported");} //查詢是否支持mark//絕大部分不支持,因此提供默認(rèn)實(shí)現(xiàn),返回false。子類有需要可以覆蓋。public boolean markSupported() { return false;} }?
2.FilterInputStream
?這是字節(jié)輸入流部分裝飾器模式的核心。是在裝飾器模式中的Decorator對(duì)象,主要完成對(duì)其它流裝飾的基本功能:
public class FilterInputStream extends InputStream {//裝飾器的代碼特征:被裝飾的對(duì)象一般是裝飾器的成員變量protected volatile InputStream in; //將要被裝飾的字節(jié)輸入流protected FilterInputStream(InputStream in) { //通過構(gòu)造方法傳入此被裝飾的流this.in = in;}//下面這些方法,完成最小的裝飾――0裝飾,只是調(diào)用被裝飾流的方法而已public int read() throws IOException {return in.read();}public int read(byte b[]) throws IOException {return read(b, 0, b.length);}public int read(byte b[], int off, int len) throws IOException {return in.read(b, off, len);}public long skip(long n) throws IOException {return in.skip(n);}public int available() throws IOException {return in.available();}public void close() throws IOException {in.close();}public synchronized void mark(int readlimit) {in.mark(readlimit);}public synchronized void reset() throws IOException {in.reset();}public boolean markSupported() {return in.markSupported();} }ByteArray到ByteArrayInputStream的適配:
ByteArrayInputStream內(nèi)部有一個(gè)byte類型的buffer。很典型的適配器模式的應(yīng)用――將byte數(shù)組適配流的接口。
public class ByteArrayInputStream extends InputStream {protected byte buf[]; //內(nèi)部的buffer,一般通過構(gòu)造器輸入protected int pos; //當(dāng)前位置的cursor。從0至byte數(shù)組的長(zhǎng)度。//byte[pos]就是read方法讀取的字節(jié)protected int mark = 0; //mark的位置。protected int count; //流中字節(jié)的數(shù)目。//構(gòu)造器,從一個(gè)byte[]創(chuàng)建一個(gè)ByteArrayInputStreampublic ByteArrayInputStream(byte buf[]) {//初始化流中的各個(gè)成員變量this.buf = buf; this.pos = 0;this.count = buf.length;}//構(gòu)造器public ByteArrayInputStream(byte buf[], int offset, int length) { this.buf = buf;this.pos = offset; //與上面不同this.count = Math.min(offset + length, buf.length);this.mark = offset; //與上面不同 }//從流中讀取下一個(gè)字節(jié)public synchronized int read() { //返回下一個(gè)位置的字節(jié)//流中沒有數(shù)據(jù)則返回-1return (pos < count) ? (buf[pos++] & 0xff) : -1; }// ByteArrayInputStream要覆蓋InputStream中可以看出其提供了該方法的實(shí)現(xiàn)//某些時(shí)候,父類不能完全實(shí)現(xiàn)子類的功能,父類的實(shí)現(xiàn)一般比較通用。//當(dāng)子類有更有效的方法時(shí),我們會(huì)覆蓋這些方法。public synchronized int read(byte b[], int off, int len) {//首先檢查輸入?yún)?shù)的狀態(tài)是否正確if(b==null){ throw new NullPointerException();} else if (off < 0 || len < 0 || len > b.length - off) {throw new IndexOutOfBoundsException();}if (pos >= count) { return -1; }if (pos + len > count) { len = count - pos; }if (len <= 0) { return 0; }//java中提供數(shù)據(jù)復(fù)制的方法//出于速度的原因!他們都用到System.arraycopy方法 System.arraycopy(buf, pos, b, off, len); pos += len;return len;}//下面這個(gè)方法,在InputStream中也已經(jīng)實(shí)現(xiàn)了。//但是當(dāng)時(shí)是通過將字節(jié)讀入一個(gè)buffer中實(shí)現(xiàn)的,好像效率低了一點(diǎn)。//比InputStream中的方法簡(jiǎn)單、高效public synchronized long skip(long n) {//當(dāng)前位置,可以跳躍的字節(jié)數(shù)目if (pos + n > count) { n = count - pos; } //小于0,則不可以跳躍if (n < 0) { return 0; } //跳躍后,當(dāng)前位置變化 pos += n; return n;} //查詢流中還有多少字節(jié)沒有讀取。 public synchronized int available() {return count - pos;}//ByteArrayInputStream支持mark所以返回truepublic boolean markSupported() { return true;} //在流中當(dāng)前位置mark。 public void mark(int readAheadLimit) { mark = pos;}//重置流。即回到mark的位置。public synchronized void reset() {pos = mark;}//關(guān)閉ByteArrayInputStream不會(huì)產(chǎn)生任何動(dòng)作。public void close() throws IOException { } }?
3.BufferedInputStream//該類主要完成對(duì)被包裝流,加上一個(gè)緩存的功能
public class BufferedInputStream extends FilterInputStream {private static int defaultBufferSize = 8192; //默認(rèn)緩存的大小protected volatile byte buf[]; //內(nèi)部的緩存protected int count; //buffer的大小protected int pos; //buffer中cursor的位置protected int markpos = -1; //mark的位置protected int marklimit; //mark的范圍//原子性更新。和一致性編程相關(guān)private static final AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater =AtomicReferenceFieldUpdater.newUpdater (BufferedInputStream.class, byte[].class,"buf");//檢查輸入流是否關(guān)閉,同時(shí)返回被包裝流private InputStream getInIfOpen() throws IOException {InputStream input = in;if (input == null) throw new IOException("Stream closed");return input;}//檢查buffer的狀態(tài),同時(shí)返回緩存private byte[] getBufIfOpen() throws IOException { byte[] buffer = buf;//不太可能發(fā)生的狀態(tài)if (buffer == null) throw new IOException("Stream closed"); return buffer;}//構(gòu)造器 public BufferedInputStream(InputStream in) {//指定默認(rèn)長(zhǎng)度的bufferthis(in, defaultBufferSize); }//構(gòu)造器public BufferedInputStream(InputStream in, int size) { super(in);//檢查輸入?yún)?shù)if(size<=0){throw new IllegalArgumentException("Buffer size <= 0");}//創(chuàng)建指定長(zhǎng)度的bufferbuf = new byte[size]; }//從流中讀取數(shù)據(jù),填充如緩存中。private void fill() throws IOException {//得到bufferbyte[] buffer = getBufIfOpen(); if (markpos < 0)//mark位置小于0,此時(shí)pos為0pos = 0;//pos大于buffer的長(zhǎng)度 else if (pos >= buffer.length) if (markpos > 0) { int sz = pos - markpos;System.arraycopy(buffer, markpos, buffer, 0, sz);pos = sz;markpos = 0;} else if (buffer.length >= marklimit) { //buffer的長(zhǎng)度大于marklimit時(shí),mark失效markpos = -1; //丟棄buffer中的內(nèi)容
pos = 0; }else{ //buffer的長(zhǎng)度小于marklimit時(shí)對(duì)buffer擴(kuò)容int nsz = pos * 2;if (nsz > marklimit) nsz = marklimit;//擴(kuò)容為原來的2倍,太大則為marklimit大小byte nbuf[] = new byte[nsz]; //將buffer中的字節(jié)拷貝如擴(kuò)容后的buf中 System.arraycopy(buffer, 0, nbuf, 0, pos); if (!bufUpdater.compareAndSet(this, buffer, nbuf)) { //在buffer在被操作時(shí),不能取代此bufferthrow new IOException("Stream closed");}//將新buf賦值給bufferbuffer = nbuf; }count = pos;int n = getInIfOpen().read(buffer, pos, buffer.length - pos);if (n > 0) count = n + pos;}//讀取下一個(gè)字節(jié)public synchronized int read() throws IOException { //到達(dá)buffer的末端 if (pos >= count) { //就從流中讀取數(shù)據(jù),填充buffer fill();
//讀過一次,沒有數(shù)據(jù)則返回-1if (pos >= count) return -1; }//返回buffer中下一個(gè)位置的字節(jié)return getBufIfOpen()[pos++] & 0xff; }//將數(shù)據(jù)從流中讀入buffer中private int read1(byte[] b, int off, int len) throws IOException { int avail = count - pos; //buffer中還剩的可讀字符 //buffer中沒有可以讀取的數(shù)據(jù)時(shí)if(avail<=0){ //將輸入流中的字節(jié)讀入b中if (len >= getBufIfOpen().length && markpos < 0) { return getInIfOpen().read(b, off, len);}fill();//填充 avail = count - pos;if (avail <= 0) return -1;}//從流中讀取后,檢查可以讀取的數(shù)目int cnt = (avail < len) ? avail : len; //將當(dāng)前buffer中的字節(jié)放入b的末端 System.arraycopy(getBufIfOpen(), pos, b, off, cnt); pos += cnt;return cnt;}public synchronized int read(byte b[], int off, int len)throws IOException {getBufIfOpen();
// 檢查buffer是否open//檢查輸入?yún)?shù)是否正確if ((off | len | (off + len) | (b.length - (off + len))) < 0) { throw new IndexOutOfBoundsException();} else if (len == 0) {return 0;}int n = 0;for (;;) {int nread = read1(b, off + n, len - n);if (nread <= 0) return (n == 0) ? nread : n;n += nread;if (n >= len) return n;InputStream input = in;if (input != null && input.available() <= 0) return n;}}public synchronized long skip(long n) throws IOException {// 檢查buffer是否關(guān)閉 getBufIfOpen(); //檢查輸入?yún)?shù)是否正確if (n <= 0) { return 0; } //buffered中可以讀取字節(jié)的數(shù)目long avail = count - pos; //可以讀取的小于0,則從流中讀取if (avail <= 0) { //mark小于0,則mark在流中 if (markpos <0) return getInIfOpen().skip(n); // 從流中讀取數(shù)據(jù),填充緩沖區(qū)。 fill(); //可以讀的取字節(jié)為buffer的容量減當(dāng)前位置avail = count - pos; if (avail <= 0) return 0;} long skipped = (avail < n) ? avail : n; pos += skipped;
//當(dāng)前位置改變return skipped;}//該方法不會(huì)block!返回流中可以讀取的字節(jié)的數(shù)目。//該方法的返回值為緩存中的可讀字節(jié)數(shù)目加流中可讀字節(jié)數(shù)目的和public synchronized int available() throws IOException {return getInIfOpen().available() + (count - pos); }//當(dāng)前位置處為mark位置public synchronized void mark(int readlimit) { marklimit = readlimit;markpos = pos;}public synchronized void reset() throws IOException {// 緩沖去關(guān)閉了,肯定就拋出異常!程序設(shè)計(jì)中經(jīng)常的手段 getBufIfOpen();if (markpos < 0) throw new IOException("Resetting to invalid mark");pos = markpos;}//該流和ByteArrayInputStream一樣都支持markpublic boolean markSupported() { return true;}//關(guān)閉當(dāng)前流同時(shí)釋放相應(yīng)的系統(tǒng)資源。public void close() throws IOException {byte[] buffer;while ( (buffer = buf) != null) {if (bufUpdater.compareAndSet(this, buffer, null)) {InputStream input = in;in = null;if (input != null) input.close();return;}// Else retry in case a new buf was CASed in fill() }} }
?
4.PipedOutputStream
?
PipedOutputStream一般必須和一個(gè)PipedInputStream連接。共同構(gòu)成一個(gè)pipe。即必須連接輸入部分。
其原理為:PipedInputStream內(nèi)部有一個(gè)Buffer, PipedInputStream可以使用InputStream的方法讀取其Buffer中的字節(jié)。PipedInputStream中Buffer中的字節(jié)是PipedOutputStream調(diào)用PipedInputStream的方法放入的。
public class PipedOutputStream extends OutputStream {//包含一個(gè)PipedInputStreamprivate PipedInputStream sink; //帶有目的地的構(gòu)造器public PipedOutputStream(PipedInputStream snk)throws IOException { connect(snk);}//默認(rèn)構(gòu)造器,必須使用下面的connect方法連接public PipedOutputStream() { }public synchronized void connect(PipedInputStream snk) throws IOException {//檢查輸入?yún)?shù)的正確性if(snk==null){ throw new NullPointerException();} else if (sink != null || snk.connected) {throw new IOException("Already connected");}//一系列初始化工作sink = snk; snk.in = -1;snk.out = 0;snk.connected = true;} //向流中寫入數(shù)據(jù)public void write(int b) throws IOException { if (sink == null) { throw new IOException("Pipe not connected"); }//本質(zhì)上是,調(diào)用PipedInputStream的receive方法接受此字節(jié) sink.receive(b); }public void write(byte b[], int off, int len) throws IOException {//首先檢查輸入?yún)?shù)的正確性if (sink == null) { throw new IOException("Pipe not connected");} else if (b == null) {throw new NullPointerException();} else if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) {throw new IndexOutOfBoundsException();} else if (len == 0) {return;}//調(diào)用PipedInputStream的receive方法接受 sink.receive(b, off, len); }//flush輸出流public synchronized void flush() throws IOException { if (sink != null) {//本質(zhì)是通知輸入流,可以讀取synchronized (sink) { sink.notifyAll(); } }}//關(guān)閉流同時(shí)釋放相關(guān)資源public void close() throws IOException { if (sink != null) { sink.receivedLast(); }} }PipedInputStream
public class PipedInputStream extends InputStream {//標(biāo)識(shí)有讀取方或?qū)懭敕疥P(guān)閉boolean closedByWriter = false; volatile boolean closedByReader = false; //是否建立連接boolean connected = false; //標(biāo)識(shí)哪個(gè)線程 Thread readSide; Thread writeSide;//緩沖區(qū)的默認(rèn)大小protected static final int PIPE_SIZE = 1024; //緩沖區(qū)protected byte buffer[] = new byte[PIPE_SIZE]; //下一個(gè)寫入字節(jié)的位置。0代表空,in==out代表滿protected int in = -1; //下一個(gè)讀取字節(jié)的位置 protected int out = 0; //給定源的輸入流public PipedInputStream(PipedOutputStream src) throws IOException { connect(src);}//默認(rèn)構(gòu)造器,下部一定要connect源public PipedInputStream() { } //連接輸入源public void connect(PipedOutputStream src) throws IOException { //調(diào)用源的connect方法連接當(dāng)前對(duì)象src.connect(this); }//只被PipedOuputStream調(diào)用protected synchronized void receive(int b) throws IOException { //檢查狀態(tài),寫入 checkStateForReceive(); //永遠(yuǎn)是PipedOuputStreamwriteSide = Thread.currentThread(); //輸入和輸出相等,等待空間if (in == out) awaitSpace(); if (in < 0) {in = 0;out = 0;}//放入buffer相應(yīng)的位置buffer[in++] = (byte)(b & 0xFF); //in為0表示buffer已空if (in >= buffer.length) { in = 0; } }synchronized void receive(byte b[], int off, int len) throws IOException {checkStateForReceive();//從PipedOutputStream可以看出writeSide = Thread.currentThread(); int bytesToTransfer = len;while (bytesToTransfer > 0) {//滿了,會(huì)通知讀取的;空會(huì)通知寫入if (in == out) awaitSpace(); int nextTransferAmount = 0;if (out < in) {nextTransferAmount = buffer.length - in;} else if (in < out) {if (in == -1) {in = out = 0;nextTransferAmount = buffer.length - in;} else {nextTransferAmount = out - in;}}if (nextTransferAmount > bytesToTransfer) nextTransferAmount = bytesToTransfer;assert(nextTransferAmount > 0);System.arraycopy(b, off, buffer, in, nextTransferAmount);bytesToTransfer -= nextTransferAmount;off += nextTransferAmount;in += nextTransferAmount;if (in >= buffer.length) { in = 0; }}}//檢查當(dāng)前狀態(tài),等待輸入private void checkStateForReceive() throws IOException { if (!connected) {throw new IOException("Pipe not connected");} else if (closedByWriter || closedByReader) {throw new IOException("Pipe closed");} else if (readSide != null && !readSide.isAlive()) {throw new IOException("Read end dead");}}//Buffer已滿,等待一段時(shí)間private void awaitSpace() throws IOException { //in==out表示滿了,沒有空間while (in == out) { //檢查接受端的狀態(tài) checkStateForReceive(); //通知讀取端 notifyAll(); try {wait(1000);} catch (InterruptedException ex) {throw new java.io.InterruptedIOException();}}}//通知所有等待的線程()已經(jīng)接受到最后的字節(jié)synchronized void receivedLast() { closedByWriter = true; // notifyAll();}public synchronized int read() throws IOException {//檢查一些內(nèi)部狀態(tài)if (!connected) { throw new IOException("Pipe not connected");} else if (closedByReader) {throw new IOException("Pipe closed");} else if (writeSide != null && !writeSide.isAlive()&& !closedByWriter && (in < 0)) {throw new IOException("Write end dead");}//當(dāng)前線程讀取readSide = Thread.currentThread(); //重復(fù)兩次???int trials = 2; while (in < 0) {//輸入斷關(guān)閉返回-1if (closedByWriter) { return -1; } //狀態(tài)錯(cuò)誤if ((writeSide != null) && (!writeSide.isAlive()) && (--trials < 0)) { throw new IOException("Pipe broken");}notifyAll(); // 空了,通知寫入端可以寫入 try {wait(1000);} catch (InterruptedException ex) {throw new java.io.InterruptedIOException();}}int ret = buffer[out++] & 0xFF; if (out >= buffer.length) { out = 0; }//沒有任何字節(jié)if (in == out) { in = -1; } return ret;}public synchronized int read(byte b[], int off, int len) throws IOException {//檢查輸入?yún)?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;}//讀取下一個(gè)int c = read(); //已經(jīng)到達(dá)末尾了,返回-1if (c < 0) { return -1; } //放入外部buffer中b[off] = (byte) c; //return-lenint rlen = 1; //下一個(gè)in存在,且沒有到達(dá)lenwhile ((in >= 0) && (--len > 0)) { //依次放入外部bufferb[off + rlen] = buffer[out++]; rlen++;//讀到buffer的末尾,返回頭部if (out >= buffer.length) { out = 0; } //讀、寫位置一致時(shí),表示沒有數(shù)據(jù)if (in == out) { in = -1; } }//返回填充的長(zhǎng)度return rlen; }//返回還有多少字節(jié)可以讀取public synchronized int available() throws IOException { //到達(dá)末端,沒有字節(jié)if(in < 0)return 0; else if(in == out)//寫入的和讀出的一致,表示滿return buffer.length; else if (in > out)//寫入的大于讀出return in - out; else//寫入的小于讀出的return in + buffer.length - out; }//關(guān)閉當(dāng)前流,同時(shí)釋放與其相關(guān)的資源public void close() throws IOException { //表示由輸入流關(guān)閉closedByReader = true; //同步化當(dāng)前對(duì)象,in為-1synchronized (this) { in = -1; } }}?
轉(zhuǎn)載于:https://www.cnblogs.com/winterfells/p/8745297.html
超強(qiáng)干貨來襲 云風(fēng)專訪:近40年碼齡,通宵達(dá)旦的技術(shù)人生總結(jié)
以上是生活随笔為你收集整理的Java源码解析——Java IO包的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java笔记(3):String(2)
- 下一篇: 20165234 《Java程序设计》第