Java BufferedReader相關(guān)源碼實(shí)例分析
1、案例代碼
假設(shè)b.txt存儲(chǔ)了abcdegfhijk
public static void main(String[] args) throws IOException {
//字符緩沖流
BufferedReader bufferedReader=new BufferedReader(new FileReader
(new File("H:\\ioText\\b.txt")),8);
//存儲(chǔ)讀取的數(shù)據(jù)
char[] charsRead=new char[5];
//讀取數(shù)據(jù)
bufferedReader.read(charsRead);
//遍歷并輸出charsRead
for (char c:charsRead){
System.out.println(c);
}
}
2、通過源碼(部分)分析案例
a、第一次讀取
public class BufferedReader extends Reader {
private Reader in;//字符流
private char cb[];//緩沖區(qū)
private int nChars, nextChar;//nChars緩沖區(qū)可讀字符數(shù),nextChar下一個(gè)字符位置
private static final int INVALIDATED = -2;
private static final int UNMARKED = -1;
private int markedChar = UNMARKED;
private int readAheadLimit = 0;
private boolean skipLF = false;
private boolean markedSkipLF = false;
private static int defaultCharBufferSize = 8192;//緩沖區(qū)默認(rèn)大小
private static int defaultExpectedLineLength = 80;
//案例調(diào)用的構(gòu)造方法
public BufferedReader(Reader in, int sz) {
//調(diào)用父類構(gòu)造
super(in);
//判斷緩沖區(qū)大小是否正常
if (sz <= 0)
throw new IllegalArgumentException("Buffer size <= 0");
//用戶傳入的字符流
this.in = in;
//給緩沖區(qū)指定空間大?。ò咐付?)
cb = new char[sz];
//緩沖區(qū)可讀字符數(shù)和下一個(gè)字符位置初始化為0
nextChar = nChars = 0;
}
//讀取數(shù)據(jù)
public int read(char cbuf[], int off, int len) throws IOException {
synchronized (lock) {
ensureOpen();
if ((off < 0) || (off > cbuf.length) || (len < 0) ||
((off + len) > cbuf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
//調(diào)用read1方法進(jìn)行讀取(真正讀取數(shù)據(jù)的方法是read1方法)
int n = read1(cbuf, off, len);
if (n <= 0) return n;
//將之前沒處理完的數(shù)據(jù)復(fù)制到自定以數(shù)組charsRead再次調(diào)用read1方法讀取
while ((n < len) && in.ready()) {
int n1 = read1(cbuf, off + n, len - n);
if (n1 <= 0) break;
n += n1;
}
return n;
}
}
//cbuf用戶自定義數(shù)組(charsRead),off=0,len=5
private int read1(char[] cbuf, int off, int len) throws IOException {
if (nextChar >= nChars) {//第一次讀nextChar、nChars都為0,滿足條件
if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {
return in.read(cbuf, off, len);
}
//刷新緩沖區(qū),先往下找到fill方法源碼分析
fill();
}
if (nextChar >= nChars) return -1;
if (skipLF) {
skipLF = false;
if (cb[nextChar] == '\n') {
nextChar++;
if (nextChar >= nChars)
fill();
if (nextChar >= nChars)
return -1;
}
}
//執(zhí)行完fill方法到這里,(len=5,nChars - nextChar=8-0)->n=5
int n = Math.min(len, nChars - nextChar);
//將緩沖區(qū)cb從nextChar開始復(fù)制n=5個(gè)字符到自定義數(shù)組
System.arraycopy(cb, nextChar, cbuf, off, n);
//nextChar=5
nextChar += n;
//n=5
return n;
}
//刷新緩沖區(qū)方法
private void fill() throws IOException {
int dst;
if (markedChar <= UNMARKED) {//markedChar初始值為UNMARKED,滿足條件
/* No mark */
dst = 0;//初始化dst
} else {
/* Marked */
int delta = nextChar - markedChar;
if (delta >= readAheadLimit) {
/* Gone past read-ahead limit: Invalidate mark */
markedChar = INVALIDATED;
readAheadLimit = 0;
dst = 0;
} else {
if (readAheadLimit <= cb.length) {
/* Shuffle in the current buffer */
System.arraycopy(cb, markedChar, cb, 0, delta);
markedChar = 0;
dst = delta;
} else {
/* Reallocate buffer to accommodate read-ahead limit */
char ncb[] = new char[readAheadLimit];
System.arraycopy(cb, markedChar, ncb, 0, delta);
cb = ncb;
markedChar = 0;
dst = delta;
}
nextChar = nChars = delta;
}
}
int n;
do {
//dst=0,cb.length - dst=8-0->n=8
n = in.read(cb, dst, cb.length - dst);
} while (n == 0);
if (n > 0) {//滿足條件
//nChars=8
nChars = dst + n;
//nextChar=0
nextChar = dst;
}
}
}
第一次讀取后charsRead存儲(chǔ)了五個(gè)字符:abcde
b、第二次讀取
//cbuf用戶自定義數(shù)組(charsRead),off=0,len=5
private int read1(char[] cbuf, int off, int len) throws IOException {
if (nextChar >= nChars) {//第二次讀nextChar=5、nChars=8,不滿足條件
if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {
return in.read(cbuf, off, len);
}
fill();
}
if (nextChar >= nChars) return -1;
if (skipLF) {
skipLF = false;
if (cb[nextChar] == '\n') {
nextChar++;
if (nextChar >= nChars)
fill();
if (nextChar >= nChars)
return -1;
}
}
//跳過if直接到這里,len=5,nChars - nextChar=8-5=3->n=3
int n = Math.min(len, nChars - nextChar);
//將緩沖區(qū)cb從nextChar=5開始復(fù)制n=3個(gè)字符到自定義數(shù)組
System.arraycopy(cb, nextChar, cbuf, off, n);
//nextChar=5+3=8
nextChar += n;
//n=8
return n;
}
第二次讀取只讀了三個(gè)字符把charsRead五個(gè)字符的前三個(gè)覆蓋:fghde
c、第三次讀取
//cbuf用戶自定義數(shù)組(charsRead),off=0,len=5
private int read1(char[] cbuf, int off, int len) throws IOException {
if (nextChar >= nChars) {//第三次讀nextChar=8、nChars=8,滿足條件
if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {
return in.read(cbuf, off, len);
}
//刷新緩沖區(qū),先往下找到fill方法源碼分析
fill();
}
if (nextChar >= nChars) return -1;
if (skipLF) {
skipLF = false;
if (cb[nextChar] == '\n') {
nextChar++;
if (nextChar >= nChars)
fill();
if (nextChar >= nChars)
return -1;
}
}
//執(zhí)行完fill方法到這里,(len=2,nChars - nextChar=8-0)->n=2
int n = Math.min(len, nChars - nextChar);
//將緩沖區(qū)cb從nextChar=0開始復(fù)制n=2個(gè)字符到自定義數(shù)組
System.arraycopy(cb, nextChar, cbuf, off, n);
//nextChar=5+3=8
nextChar += n;
//n=8
return n;
}
//刷新緩沖區(qū)方法
private void fill() throws IOException {
int dst;
if (markedChar <= UNMARKED) {//markedChar初始值為UNMARKED,滿足條件
/* No mark */
dst = 0;//初始化dst
} else {
/* Marked */
int delta = nextChar - markedChar;
if (delta >= readAheadLimit) {
/* Gone past read-ahead limit: Invalidate mark */
markedChar = INVALIDATED;
readAheadLimit = 0;
dst = 0;
} else {
if (readAheadLimit <= cb.length) {
/* Shuffle in the current buffer */
System.arraycopy(cb, markedChar, cb, 0, delta);
markedChar = 0;
dst = delta;
} else {
/* Reallocate buffer to accommodate read-ahead limit */
char ncb[] = new char[readAheadLimit];
System.arraycopy(cb, markedChar, ncb, 0, delta);
cb = ncb;
markedChar = 0;
dst = delta;
}
nextChar = nChars = delta;
}
}
int n;
do {
//dst=0,cb.length - dst=8-0->n=8
n = in.read(cb, dst, cb.length - dst);
} while (n == 0);
if (n > 0) {//滿足條件
//nChars=8
nChars = dst + n;
//nextChar=0
nextChar = dst;
}
}
}
第三次讀取了兩個(gè)字符到charsRead,把最后兩個(gè)字符覆蓋:fghijk
3、源碼執(zhí)行過程圖解

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
java的GUI實(shí)現(xiàn)簡(jiǎn)單切換界面
這篇文章主要為大家詳細(xì)介紹了java的GUI實(shí)現(xiàn)簡(jiǎn)單切換界面,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04
Spring?Data?JPA?實(shí)體類中常用注解說明
這篇文章主要介紹了Spring?Data?JPA?實(shí)體類中常用注解說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
詳解SpringBoot簡(jiǎn)化配置分析總結(jié)
這篇文章主要介紹了詳解SpringBoot簡(jiǎn)化配置分析總結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10
Java正則驗(yàn)證電話,手機(jī),郵箱,日期,金額的方法示例
這篇文章主要介紹了Java正則驗(yàn)證電話,手機(jī),郵箱,日期,金額的方法,結(jié)合具體實(shí)例形式分析了Java針對(duì)電話,手機(jī),郵箱,日期,金額的正則判定操作技巧,需要的朋友可以參考下2017-03-03
Java中關(guān)于char類型變量能夠輸出中文的問題
這篇文章主要介紹了Java中關(guān)于char類型變量能夠輸出中文的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12
SpringBoot中使用攔截器攔截跳轉(zhuǎn)登錄的兩種實(shí)現(xiàn)方法
攔截器(Interceptor)是Spring框架提供的一種機(jī)制,用于在請(qǐng)求的生命周期中插入自定義邏輯,如身份驗(yàn)證、日志記錄等,本文將詳細(xì)介紹兩種在SpringBoot中使用攔截器來控制用戶登錄并跳轉(zhuǎn)到指定頁面的方法,需要的朋友可以參考下2024-11-11
mybatis的動(dòng)態(tài)SQL以及連接池詳解
這篇文章主要介紹了mybatis的動(dòng)態(tài)SQL以及連接池詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02

