概況
Reader 是一個用於讀字元流的抽象類,它將一些相通的讀相關操作抽象到此類,方便各種讀操作類的實現。一般來說子類只需要實現它的 read 和 close 兩個方法,但如果有需要還可以重寫 Reader 提供的公共方法。
JDK 在 Reader 的基礎上實現了很多有用的 xxxReader ,包括 BufferedReader、CharArrayReader、FilterReader、InputStreamReader、FileReader、PipedReader、StringReader 和 LineNumberReader 等等。
繼承結構
--java.lang.Object
--java.io.Reader
複製程式碼
類定義
public abstract class Reader implements Readable, Closeable
複製程式碼
Reader 被定為 public 且 abstract 的類,實現了 Readable 和 Closeable介面。
Readable 介面表示嘗試將字元讀取到指定的緩衝中,介面定義如下:
public interface Readable {
public int read(java.nio.CharBuffer cb) throws IOException;
}
複製程式碼
Closeable 介面表示 Reader 可以被close,介面定義如下:
public interface Closeable extends AutoCloseable {
public void close() throws IOException;
}
複製程式碼
主要屬性
private static final int maxSkipBufferSize = 8192;
private char skipBuffer[] = null;
protected Object lock;
複製程式碼
- maxSkipBufferSize 最大跳過緩衝的大小。
- skipBuffer 是一個 char[] 型別,表示跳過緩衝。
- lock 是 Reader 的鎖,用於實現同步。
構造方法
有兩種構造方法,不帶引數時則將自己作為鎖,而如果傳入了某個 Object 物件則將其作為鎖。
protected Reader() {
this.lock = this;
}
protected Reader(Object lock) {
if (lock == null) {
throw new NullPointerException();
}
this.lock = lock;
}
複製程式碼
主要方法
read方法
一共有四個 read 方法,其中有一個抽象的 read 方法,可以看到所有 read 方法最終都會呼叫這個抽象方法,提供給子類處理邏輯的實現。它傳入的三個引數,字元陣列cbuf、偏移量off和陣列長度。
public abstract int read(char cbuf[], int off, int len) throws IOException;
複製程式碼
無參的 read 方法其實是預設讀一個字元,new 一個 char 物件然後呼叫子類實現進行讀取,最後返回讀到的字元。
public int read() throws IOException {
char cb[] = new char[1];
if (read(cb, 0, 1) == -1)
return -1;
else
return cb[0];
}
複製程式碼
假如 read 方法傳入的引數為 char 陣列時,則直接呼叫子類實現進行讀取。
public int read(char cbuf[]) throws IOException {
return read(cbuf, 0, cbuf.length);
}
複製程式碼
最後一個 read 方法其實是 Readable 介面定義的方法,用於讀取字元到指定的 CharBuffer 物件中,邏輯是先得到 CharBuffer 物件剩餘長度,根據該長度例項化 char 陣列,然後呼叫子類實現完成讀取,最後將讀取到的字元放進 CharBuffer 物件。
public int read(java.nio.CharBuffer target) throws IOException {
int len = target.remaining();
char[] cbuf = new char[len];
int n = read(cbuf, 0, len);
if (n > 0)
target.put(cbuf, 0, n);
return n;
}
複製程式碼
ready方法
表示該讀取器是否已準備好,預設返回 false,如果能保證呼叫 read 方法讀取下一個字元不阻塞則返回 true。
public boolean ready() throws IOException {
return false;
}
複製程式碼
skip方法
該方法用於跳過指定長度字元,期間如果某些字元還未可讀則可能發生阻塞,另外期間如果發生 IO 錯誤則會拋異常。邏輯是,
- 跳過字元長度不能小於0。
- 跳過長度不能超過最大跳過長度 maxSkipBufferSize,超過則只能取 maxSkipBufferSize。
- 加鎖開始處理,skipBuffer 物件如果為空則需要先例項化指定長度的 char 陣列。
- 不斷迴圈呼叫子類的 read 方法進行讀取,對讀取到的字元不做處理,即實現了跳過效果。
public long skip(long n) throws IOException {
if (n < 0L)
throw new IllegalArgumentException("skip value is negative");
int nn = (int) Math.min(n, maxSkipBufferSize);
synchronized (lock) {
if ((skipBuffer == null) || (skipBuffer.length < nn))
skipBuffer = new char[nn];
long r = n;
while (r > 0) {
int nc = read(skipBuffer, 0, (int)Math.min(r, nn));
if (nc == -1)
break;
r -= nc;
}
return n - r;
}
}
複製程式碼
close方法
它是一個抽象方法,留給子類實現。此方法用於關閉流,並且釋放相關的資源 。關閉後再呼叫 read()、ready()、mark()、reset()或skip()等方法將丟擲 IO 異常。
public abstract void close() throws IOException;
複製程式碼
markSupported方法
是否支援 mark 和 reset 操作,這裡直接返回 false,子類根據實際重寫該方法。
public boolean markSupported() {
return false;
}
複製程式碼
mark方法
標記讀取器當前的位置,與之對應的是 reset 方法,通過他們之間的組合能實現重複讀取操作。預設是不支援此操作的,需要子類重寫該方法。
public void mark(int readAheadLimit) throws IOException {
throw new IOException("mark() not supported");
}
複製程式碼
reset方法
與 mark 方法對應,它可以重置讀取器的位置到上次被 mark 操作標識的位置,如果未被標記過則可能會被重置到開始的位置。預設是不支援此操作的,需要子類重寫該方法。
public void reset() throws IOException {
throw new IOException("reset() not supported");
}
複製程式碼
=============廣告時間===============
公眾號的選單已分為“分散式”、“機器學習”、“深度學習”、“NLP”、“Java深度”、“Java併發核心”、“JDK原始碼”、“Tomcat核心”等,可能有一款適合你的胃口。
鄙人的新書《Tomcat核心設計剖析》已經在京東銷售了,有需要的朋友可以購買。感謝各位朋友。
=========================
歡迎關注: