java原始碼-BufferedReader
開篇
在設計模式中有一種叫做裝飾者模式,剛好BufferedReader的原始碼是這個設計模式的最好例子,一併看下原始碼。
原始碼分析
建構函式
- BufferedReader的類變數的Reader in 用以建構函式引數中的Reader in引數,BufferedReader的所有讀寫操作都通過Reader物件進行操作。
- BufferedReader相當於針對內部的Reader物件進行了一層包裝,可以理解為裝飾者。
public class BufferedReader extends Reader {
private Reader in;
private char cb[];
//nextChar代表下次要讀取的位置,nChars表示總共的字元個數
private int nChars, nextChar;
private static final int INVALIDATED = -2;
private static final int UNMARKED = -1;
private int markedChar = UNMARKED;
private int readAheadLimit = 0; /* Valid only when markedChar > 0 */
private boolean skipLF = false;
private boolean markedSkipLF = false;
private static int defaultCharBufferSize = 8192;
private static int defaultExpectedLineLength = 80;
public BufferedReader(Reader in, int sz) {
super(in);
if (sz <= 0)
throw new IllegalArgumentException("Buffer size <= 0");
this.in = in;
cb = new char[sz];
nextChar = nChars = 0;
}
public BufferedReader(Reader in) {
this(in, defaultCharBufferSize);
}
}
載入資料
- 負責通過Reader in物件讀取字元到指定數量的字元資料到cb陣列當中。
- dst表示儲存資料的起始位置,cb.length-dst表示讀取字元的個數。
- 在執行read和readline操作的之前如果cb當中可讀字元不足會先執行fill()讀取字元。
private void fill() throws IOException {
int dst;
if (markedChar <= UNMARKED) {
/* No mark */
dst = 0;
} else {
// 省略一部分程式碼
}
int n;
do {
// 從底層input讀取資料到cb,cb中起始位置是dst,
// 讀取的長度是cb的lenght減去起始位置dst,理解剩餘能夠裝的字元
n = in.read(cb, dst, cb.length - dst);
} while (n == 0);
if (n > 0) {
// 設定最大可讀字元結束位置
nChars = dst + n;
// 設定可讀字元的起始位置
nextChar = dst;
}
}
read過程
- 讀取過程中如果滿足條件(nextChar 表示下一個讀取字元>= nChars可用字元),代表字元已經讀取完畢那麼就通過fill()進行預載入。
- 讀取當前字元並累加當前可讀取字元,執行nextChar++操作。
public int read() throws IOException {
synchronized (lock) {
ensureOpen();
for (;;) {
if (nextChar >= nChars) {
fill();
if (nextChar >= nChars)
return -1;
}
if (skipLF) {
skipLF = false;
if (cb[nextChar] == '\n') {
nextChar++;
continue;
}
}
// 讀取當前字元並累加下一個讀取位置
return cb[nextChar++];
}
}
}
readline過程
- 讀取過程中如果滿足條件(nextChar 表示下一個讀取字元>= nChars可用字元),代表字元已經讀取完畢那麼就通過fill()進行預載入。
- 讀取過程中如果遇到\r\n則中斷迴圈,通過str = new String(cb, startChar, i - startChar)返回整行資料。
String readLine(boolean ignoreLF) throws IOException {
//讀取的資料最終放在這個s中,
StringBuffer s = null;
int startChar;
synchronized (lock) {
ensureOpen();
boolean omitLF = ignoreLF || skipLF;
bufferLoop:
for (;;) {
if (nextChar >= nChars)
fill();
if (nextChar >= nChars) { /* EOF */
if (s != null && s.length() > 0)
//從這裡返回,可能是因為讀取的資料最後沒有以\n或\r結束
return s.toString();
else
// 從這裡返回,是因為開始讀的時候,就已經是input的末尾了,
// 所以s本身就沒有被初始化,只能返回null
return null;
}
boolean eol = false;
char c = 0;
int i;
/* Skip a leftover '\n', if necessary */
if (omitLF && (cb[nextChar] == '\n'))
nextChar++;
skipLF = false;
omitLF = false;
charLoop:
for (i = nextChar; i < nChars; i++) {
c = cb[i];
if ((c == '\n') || (c == '\r')) {
eol = true;
break charLoop;
}
}
startChar = nextChar;
nextChar = i;
if (eol) {
String str;
// 執行到這,s為null,說明是第一次迴圈中就讀到了行尾。
if (s == null) {
str = new String(cb, startChar, i - startChar);
} else {
// 執行到這,起碼說明是第二次迴圈了,s裡已經有了第一次讀取的資料
s.append(cb, startChar, i - startChar);
str = s.toString();
}
nextChar++;
if (c == '\r') {
skipLF = true;
}
// 執行到這說明讀到了行尾,返回str
return str;
}
if (s == null)
s = new StringBuffer(defaultExpectedLineLength);
// 執行到這說明,讀取了整個cb的資料,發現一直沒有\n或者\r,
// 之後回到最初迴圈繼續讀取。
s.append(cb, startChar, i - startChar);
}
}
}
類依賴圖
-
BufferedReader的類依賴圖如下圖,所有的io reader都是繼承自Reader作為基類。
裝飾設計模式
裝飾設計模式:javaIO技術中的裝飾設計模式,對一組物件的功能進行增強時,就可以使用該設計模式
相關文章
- java學習(BufferedReader & InputStreamReader 用法)Java
- Java IO6:字元流進階及BufferedWriter、BufferedReaderJava字元
- BufferedReader和Scanner的用法和區別(建議多使用BufferedReader)
- java原始碼-CountDownLatchJava原始碼CountDownLatch
- java原始碼-SemaphoreJava原始碼
- Java集合原始碼剖析——ArrayList原始碼剖析Java原始碼
- 【Java集合原始碼剖析】ArrayList原始碼剖析Java原始碼
- 【Java集合原始碼剖析】Vector原始碼剖析Java原始碼
- 【Java集合原始碼剖析】HashMap原始碼剖析Java原始碼HashMap
- 【Java集合原始碼剖析】Hashtable原始碼剖析Java原始碼
- 【Java集合原始碼剖析】TreeMap原始碼剖析Java原始碼
- Java容器原始碼學習--ArrayList原始碼分析Java原始碼
- 【Java集合原始碼剖析】LinkedList原始碼剖析Java原始碼
- 【Java集合原始碼剖析】LinkedHashmap原始碼剖析Java原始碼HashMap
- java原始碼-java.util.ListJava原始碼
- java 原始碼分析 —BooleanJava原始碼Boolean
- java原始碼-AtomicReferenceJava原始碼
- java原始碼-AtomicIntegerJava原始碼
- Java——HashMap原始碼解析JavaHashMap原始碼
- Java——ArrayList原始碼解析Java原始碼
- Java 原始碼如何分析?Java原始碼
- Java原始碼系列 -- HashSetJava原始碼
- 搞懂 Java ArrayList 原始碼Java原始碼
- Java:HashMap原始碼分析JavaHashMap原始碼
- 搞懂 Java HashMap 原始碼JavaHashMap原始碼
- Java Collections 原始碼分析Java原始碼
- Java WeakHashMap 原始碼解析JavaHashMap原始碼
- Java TreeMap 原始碼解析Java原始碼
- Java集合類原始碼Java原始碼
- Java 原始碼,反碼和補碼Java原始碼
- 【Java集合原始碼剖析】Java集合框架Java原始碼框架
- Java String原始碼分析Java原始碼
- 如何閱讀Java原始碼?Java原始碼
- 【Java】ServiceLoader原始碼分析Java原始碼
- 【Java原始碼】集合類-ArrayDequeJava原始碼
- Java LinkedList 原始碼剖析Java原始碼
- 【Java集合】ArrayList原始碼分析Java原始碼
- java原始碼-ThreadPoolExecutor(2)Java原始碼thread