Java 中的 BufferedReader 介紹_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理
BufferedReader 介紹
BufferedReader 是緩沖字符輸入流。它繼承于Reader。
BufferedReader 的作用是為其他字符輸入流添加一些緩沖功能。
BufferedReader 函數(shù)列表
BufferedReader(Reader in) BufferedReader(Reader in, int size) void close() void mark(int markLimit) boolean markSupported() int read() int read(char[] buffer, int offset, int length) String readLine() boolean ready() void reset() long skip(long charCount)
BufferedReader 源碼分析(基于jdk1.7.40)
package java.io;
public class BufferedReader extends Reader {
private Reader in;
// 字符緩沖區(qū)
private char cb[];
// nChars 是cb緩沖區(qū)中字符的總的個(gè)數(shù)
// nextChar 是下一個(gè)要讀取的字符在cb緩沖區(qū)中的位置
private int nChars, nextChar;
// 表示“標(biāo)記無(wú)效”。它與UNMARKED的區(qū)別是:
// (01) UNMARKED 是壓根就沒(méi)有設(shè)置過(guò)標(biāo)記。
// (02) 而INVALIDATED是設(shè)置了標(biāo)記,但是被標(biāo)記位置太長(zhǎng),導(dǎo)致標(biāo)記無(wú)效!
private static final int INVALIDATED = -2;
// 表示沒(méi)有設(shè)置“標(biāo)記”
private static final int UNMARKED = -1;
// “標(biāo)記”
private int markedChar = UNMARKED;
// “標(biāo)記”能標(biāo)記位置的最大長(zhǎng)度
private int readAheadLimit = 0; /* Valid only when markedChar > 0 */
// skipLF(即skip Line Feed)是“是否忽略換行符”標(biāo)記
private boolean skipLF = false;
// 設(shè)置“標(biāo)記”時(shí),保存的skipLF的值
private boolean markedSkipLF = false;
// 默認(rèn)字符緩沖區(qū)大小
private static int defaultCharBufferSize = 8192;
// 默認(rèn)每一行的字符個(gè)數(shù)
private static int defaultExpectedLineLength = 80;
// 創(chuàng)建“Reader”對(duì)應(yīng)的BufferedReader對(duì)象,sz是BufferedReader的緩沖區(qū)大小
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;
}
// 創(chuàng)建“Reader”對(duì)應(yīng)的BufferedReader對(duì)象,默認(rèn)的BufferedReader緩沖區(qū)大小是8k
public BufferedReader(Reader in) {
this(in, defaultCharBufferSize);
}
// 確?!癇ufferedReader”是打開(kāi)狀態(tài)
private void ensureOpen() throws IOException {
if (in == null)
throw new IOException("Stream closed");
}
// 填充緩沖區(qū)函數(shù)。有以下兩種情況被調(diào)用:
// (01) 緩沖區(qū)沒(méi)有數(shù)據(jù)時(shí),通過(guò)fill()可以向緩沖區(qū)填充數(shù)據(jù)。
// (02) 緩沖區(qū)數(shù)據(jù)被讀完,需更新時(shí),通過(guò)fill()可以更新緩沖區(qū)的數(shù)據(jù)。
private void fill() throws IOException {
// dst表示“cb中填充數(shù)據(jù)的起始位置”。
int dst;
if (markedChar <= UNMARKED) {
// 沒(méi)有標(biāo)記的情況,則設(shè)dst=0。
dst = 0;
} else {
// delta表示“當(dāng)前標(biāo)記的長(zhǎng)度”,它等于“下一個(gè)被讀取字符的位置”減去“標(biāo)記的位置”的差值;
int delta = nextChar - markedChar;
if (delta >= readAheadLimit) {
// 若“當(dāng)前標(biāo)記的長(zhǎng)度”超過(guò)了“標(biāo)記上限(readAheadLimit)”,
// 則丟棄標(biāo)記!
markedChar = INVALIDATED;
readAheadLimit = 0;
dst = 0;
} else {
if (readAheadLimit <= cb.length) {
// 若“當(dāng)前標(biāo)記的長(zhǎng)度”沒(méi)有超過(guò)了“標(biāo)記上限(readAheadLimit)”,
// 并且“標(biāo)記上限(readAheadLimit)”小于/等于“緩沖的長(zhǎng)度”;
// 則先將“下一個(gè)要被讀取的位置,距離我們標(biāo)記的置符的距離”間的字符保存到cb中。
System.arraycopy(cb, markedChar, cb, 0, delta);
markedChar = 0;
dst = delta;
} else {
// 若“當(dāng)前標(biāo)記的長(zhǎng)度”沒(méi)有超過(guò)了“標(biāo)記上限(readAheadLimit)”,
// 并且“標(biāo)記上限(readAheadLimit)”大于“緩沖的長(zhǎng)度”;
// 則重新設(shè)置緩沖區(qū)大小,并將“下一個(gè)要被讀取的位置,距離我們標(biāo)記的置符的距離”間的字符保存到cb中。
char ncb[] = new char[readAheadLimit];
System.arraycopy(cb, markedChar, ncb, 0, delta);
cb = ncb;
markedChar = 0;
dst = delta;
}
// 更新nextChar和nChars
nextChar = nChars = delta;
}
}
int n;
do {
// 從“in”中讀取數(shù)據(jù),并存儲(chǔ)到字符數(shù)組cb中;
// 從cb的dst位置開(kāi)始存儲(chǔ),讀取的字符個(gè)數(shù)是cb.length - dst
// n是實(shí)際讀取的字符個(gè)數(shù);若n==0(即一個(gè)也沒(méi)讀到),則繼續(xù)讀取!
n = in.read(cb, dst, cb.length - dst);
} while (n == 0);
// 如果從“in”中讀到了數(shù)據(jù),則設(shè)置nChars(cb中字符的數(shù)目)=dst+n,
// 并且nextChar(下一個(gè)被讀取的字符的位置)=dst。
if (n > 0) {
nChars = dst + n;
nextChar = dst;
}
}
// 從BufferedReader中讀取一個(gè)字符,該字符以int的方式返回
public int read() throws IOException {
synchronized (lock) {
ensureOpen();
for (;;) {
// 若“緩沖區(qū)的數(shù)據(jù)已經(jīng)被讀完”,
// 則先通過(guò)fill()更新緩沖區(qū)數(shù)據(jù)
if (nextChar >= nChars) {
fill();
if (nextChar >= nChars)
return -1;
}
// 若要“忽略換行符”,
// 則對(duì)下一個(gè)字符是否是換行符進(jìn)行處理。
if (skipLF) {
skipLF = false;
if (cb[nextChar] == '\n') {
nextChar++;
continue;
}
}
// 返回下一個(gè)字符
return cb[nextChar++];
}
}
}
// 將緩沖區(qū)中的數(shù)據(jù)寫(xiě)入到數(shù)組cbuf中。off是數(shù)組cbuf中的寫(xiě)入起始位置,len是寫(xiě)入長(zhǎng)度
private int read(char[] cbuf, int off, int len) throws IOException {
// 若“緩沖區(qū)的數(shù)據(jù)已經(jīng)被讀完”,則更新緩沖區(qū)數(shù)據(jù)。
if (nextChar >= nChars) {
if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {
return in.read(cbuf, off, len);
}
fill();
}
// 若更新數(shù)據(jù)之后,沒(méi)有任何變化;則退出。
if (nextChar >= nChars) return -;
// 若要“忽略換行符”,則進(jìn)行相應(yīng)處理
if (skipLF) {
skipLF = false;
if (cb[nextChar] == '\n') {
nextChar++;
if (nextChar >= nChars)
fill();
if (nextChar >= nChars)
return -1;
}
}
// 拷貝字符操作
int n = Math.min(len, nChars - nextChar);
System.arraycopy(cb, nextChar, cbuf, off, n);
nextChar += n;
return n;
}
// 對(duì)read()的封裝,添加了“同步處理”和“阻塞式讀取”等功能
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;
}
int n = read1(cbuf, off, len);
if (n <= 0) return n;
while ((n < len) && in.ready()) {
int n1 = read1(cbuf, off + n, len - n);
if (n1 <= 0) break;
n += n1;
}
return n;
}
}
// 讀取一行數(shù)據(jù)。ignoreLF是“是否忽略換行符”
String readLine(boolean ignoreLF) throws IOException {
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)
return s.toString();
else
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;
if (s == null) {
str = new String(cb, startChar, i - startChar);
} else {
s.append(cb, startChar, i - startChar);
str = s.toString();
}
nextChar++;
if (c == '\r') {
skipLF = true;
}
return str;
}
if (s == null)
s = new StringBuffer(defaultExpectedLineLength);
s.append(cb, startChar, i - startChar);
}
}
}
// 讀取一行數(shù)據(jù)。不忽略換行符
public String readLine() throws IOException {
return readLine(false);
}
// 跳過(guò)n個(gè)字符
public long skip(long n) throws IOException {
if (n < 0L) {
throw new IllegalArgumentException("skip value is negative");
}
synchronized (lock) {
ensureOpen();
long r = n;
while (r > 0) {
if (nextChar >= nChars)
fill();
if (nextChar >= nChars) /* EOF */
break;
if (skipLF) {
skipLF = false;
if (cb[nextChar] == '\n') {
nextChar++;
}
}
long d = nChars - nextChar;
if (r <= d) {
nextChar += r;
r = 0;
break;
}
else {
r -= d;
nextChar = nChars;
}
}
return n - r;
}
}
// “下一個(gè)字符”是否可讀
public boolean ready() throws IOException {
synchronized (lock) {
ensureOpen();
// 若忽略換行符為true;
// 則判斷下一個(gè)符號(hào)是否是換行符,若是的話,則忽略
if (skipLF) {
if (nextChar >= nChars && in.ready()) {
fill();
}
if (nextChar < nChars) {
if (cb[nextChar] == '\n')
nextChar++;
skipLF = false;
}
}
return (nextChar < nChars) || in.ready();
}
}
// 始終返回true。因?yàn)锽ufferedReader支持mark(), reset()
public boolean markSupported() {
return true;
}
// 標(biāo)記當(dāng)前BufferedReader的下一個(gè)要讀取位置。關(guān)于readAheadLimit的作用,參考后面的說(shuō)明。
public void mark(int readAheadLimit) throws IOException {
if (readAheadLimit < 0) {
throw new IllegalArgumentException("Read-ahead limit < 0");
}
synchronized (lock) {
ensureOpen();
// 設(shè)置readAheadLimit
this.readAheadLimit = readAheadLimit;
// 保存下一個(gè)要讀取的位置
markedChar = nextChar;
// 保存“是否忽略換行符”標(biāo)記
markedSkipLF = skipLF;
}
}
// 重置BufferedReader的下一個(gè)要讀取位置,
// 將其還原到mark()中所保存的位置。
public void reset() throws IOException {
synchronized (lock) {
ensureOpen();
if (markedChar < 0)
throw new IOException((markedChar == INVALIDATED)
? "Mark invalid"
: "Stream not marked");
nextChar = markedChar;
skipLF = markedSkipLF;
}
}
public void close() throws IOException {
synchronized (lock) {
if (in == null)
return;
in.close();
in = null;
cb = null;
}
}
}
說(shuō)明:
要想讀懂BufferReader的源碼,就要先理解它的思想。BufferReader的作用是為其它Reader提供緩沖功能。創(chuàng)建BufferReader時(shí),我們會(huì)通過(guò)它的構(gòu)造函數(shù)指定某個(gè)Reader為參數(shù)。BufferReader會(huì)將該Reader中的數(shù)據(jù)分批讀取,每次讀取一部分到緩沖中;操作完緩沖中的這部分?jǐn)?shù)據(jù)之后,再?gòu)腞eader中讀取下一部分的數(shù)據(jù)。
為什么需要緩沖呢?原因很簡(jiǎn)單,效率問(wèn)題!緩沖中的數(shù)據(jù)實(shí)際上是保存在內(nèi)存中,而原始數(shù)據(jù)可能是保存在硬盤(pán)或NandFlash中;而我們知道,從內(nèi)存中讀取數(shù)據(jù)的速度比從硬盤(pán)讀取數(shù)據(jù)的速度至少快10倍以上。
那干嘛不干脆一次性將全部數(shù)據(jù)都讀取到緩沖中呢?第一,讀取全部的數(shù)據(jù)所需要的時(shí)間可能會(huì)很長(zhǎng)。第二,內(nèi)存價(jià)格很貴,容量不想硬盤(pán)那么大。
下面,我就BufferReader中最重要的函數(shù)fill()進(jìn)行說(shuō)明。其它的函數(shù)很容易理解,我就不詳細(xì)介紹了,大家可以參考源碼中的注釋進(jìn)行理解。我們先看看fill()的源碼:
private void fill() throws IOException {
int dst;
if (markedChar <= UNMARKED) {
/* No mark */
dst = 0;
} 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 {
n = in.read(cb, dst, cb.length - dst);
} while (n == 0);
if (n > 0) {
nChars = dst + n;
nextChar = dst;
}
}
根據(jù)fill()中的if...else...,我將fill()分為4種情況進(jìn)行說(shuō)明。
情況1:讀取完緩沖區(qū)的數(shù)據(jù),并且緩沖區(qū)沒(méi)有被標(biāo)記
執(zhí)行流程如下,
(01) 其它函數(shù)調(diào)用 fill(),來(lái)更新緩沖區(qū)的數(shù)據(jù)
(02) fill() 執(zhí)行代碼 if (markedChar <= UNMARKED) { ... }
為了方便分析,我們將這種情況下fill()執(zhí)行的操作等價(jià)于以下代碼:
private void fill() throws IOException {
int dst;
if (markedChar <= UNMARKED) {
/* No mark */
dst = 0;
}
int n;
do {
n = in.read(cb, dst, cb.length - dst);
} while (n == 0);
if (n > 0) {
nChars = dst + n;
nextChar = dst;
}
}
說(shuō)明:
這種情況發(fā)生的情況是 — — Reader中有很長(zhǎng)的數(shù)據(jù),我們每次從中讀取一部分?jǐn)?shù)據(jù)到緩沖中進(jìn)行操作。每次當(dāng)我們讀取完緩沖中的數(shù)據(jù)之后,并且此時(shí)BufferedReader沒(méi)有被標(biāo)記;那么,就接著從Reader(BufferReader提供緩沖功能的Reader)中讀取下一部分的數(shù)據(jù)到緩沖中。
其中,判斷是否讀完緩沖區(qū)中的數(shù)據(jù),是通過(guò)“比較nextChar和nChars之間大小”來(lái)判斷的。其中,nChars 是緩沖區(qū)中字符的總的個(gè)數(shù),而 nextChar 是緩沖區(qū)中下一個(gè)要讀取的字符的位置。
判斷BufferedReader有沒(méi)有被標(biāo)記,是通過(guò)“markedChar”來(lái)判斷的。
理解這個(gè)思想之后,我們?cè)賹?duì)這種情況下的fill()的代碼進(jìn)行分析,就特別容易理解了。
(01) if (markedChar <= UNMARKED) 它的作用是判斷“BufferedReader是否被標(biāo)記”。若被標(biāo)記,則dst=0。
(02) in.read(cb, dst, cb.length - dst) 等價(jià)于 in.read(cb, 0, cb.length),意思是從Reader對(duì)象in中讀取cb.length個(gè)數(shù)據(jù),并存儲(chǔ)到緩沖區(qū)cb中,而且從緩沖區(qū)cb的位置0開(kāi)始存儲(chǔ)。該函數(shù)返回值等于n,也就是n表示實(shí)際讀取的字符個(gè)數(shù)。若n=0(即沒(méi)有讀取到數(shù)據(jù)),則繼續(xù)讀取,直到讀到數(shù)據(jù)為止。
(03) nChars=dst+n 等價(jià)于 nChars=n;意味著,更新緩沖區(qū)數(shù)據(jù)cb之后,設(shè)置nChars(緩沖區(qū)的數(shù)據(jù)個(gè)數(shù))為n。
(04) nextChar=dst 等價(jià)于 nextChar=0;意味著,更新緩沖區(qū)數(shù)據(jù)cb之后,設(shè)置nextChar(緩沖區(qū)中下一個(gè)會(huì)被讀取的字符的索引值)為0。
情況2:讀取完緩沖區(qū)的數(shù)據(jù),緩沖區(qū)的標(biāo)記位置>0,并且“當(dāng)前標(biāo)記的長(zhǎng)度”超過(guò)“標(biāo)記上限(readAheadLimit)”
執(zhí)行流程如下,
(01) 其它函數(shù)調(diào)用 fill(),來(lái)更新緩沖區(qū)的數(shù)據(jù)
(02) fill() 執(zhí)行代碼 if (delta >= readAheadLimit) { ... }
為了方便分析,我們將這種情況下fill()執(zhí)行的操作等價(jià)于以下代碼:
private void fill() throws IOException {
int dst;
if (markedChar > UNMARKED) {
int delta = nextChar - markedChar;
if (delta >= readAheadLimit) {
markedChar = INVALIDATED;
readAheadLimit = 0;
dst = 0;
}
}
int n;
do {
n = in.read(cb, dst, cb.length - dst);
} while (n == 0);
if (n > 0) {
nChars = dst + n;
nextChar = dst;
}
}
說(shuō)明:
這種情況發(fā)生的情況是 — — BufferedReader中有很長(zhǎng)的數(shù)據(jù),我們每次從中讀取一部分?jǐn)?shù)據(jù)到緩沖區(qū)中進(jìn)行操作。當(dāng)我們讀取完緩沖區(qū)中的數(shù)據(jù)之后,并且此時(shí),BufferedReader存在標(biāo)記時(shí),同時(shí),“當(dāng)前標(biāo)記的長(zhǎng)度”大于“標(biāo)記上限”;那么,就發(fā)生情況2。此時(shí),我們會(huì)丟棄“標(biāo)記”并更新緩沖區(qū)。
(01) delta = nextChar - markedChar;其中,delta就是“當(dāng)前標(biāo)記的長(zhǎng)度”,它是“下一個(gè)被讀取字符的位置”減去“被標(biāo)記的位置”的差值。
(02) if (delta >= readAheadLimit);其中,當(dāng)delta >= readAheadLimit,就意味著,“當(dāng)前標(biāo)記的長(zhǎng)度”>=“標(biāo)記上限”。為什么要有標(biāo)記上限,即readAheadLimit的值到底有何意義呢?
我們標(biāo)記一個(gè)位置之后,更新緩沖區(qū)的時(shí)候,被標(biāo)記的位置會(huì)被保存;當(dāng)我們不停的更新緩沖區(qū)的時(shí)候,被標(biāo)記的位置會(huì)被不停的放大。然后內(nèi)存的容量是有效的,我們不可能不限制長(zhǎng)度的存儲(chǔ)標(biāo)記。所以,需要readAheadLimit來(lái)限制標(biāo)記長(zhǎng)度!
(03) in.read(cb, dst, cb.length - dst) 等價(jià)于 in.read(cb, 0, cb.length),意思是從Reader對(duì)象in中讀取cb.length個(gè)數(shù)據(jù),并存儲(chǔ)到緩沖區(qū)cb中,而且從緩沖區(qū)cb的位置0開(kāi)始存儲(chǔ)。該函數(shù)返回值等于n,也就是n表示實(shí)際讀取的字符個(gè)數(shù)。若n=0(即沒(méi)有讀取到數(shù)據(jù)),則繼續(xù)讀取,直到讀到數(shù)據(jù)為止。
(04) nChars=dst+n 等價(jià)于 nChars=n;意味著,更新緩沖區(qū)數(shù)據(jù)cb之后,設(shè)置nChars(緩沖區(qū)的數(shù)據(jù)個(gè)數(shù))為n。
(05) nextChar=dst 等價(jià)于 nextChar=0;意味著,更新緩沖區(qū)數(shù)據(jù)cb之后,設(shè)置nextChar(緩沖區(qū)中下一個(gè)會(huì)被讀取的字符的索引值)為0。
情況3:讀取完緩沖區(qū)的數(shù)據(jù),緩沖區(qū)的標(biāo)記位置>0,“當(dāng)前標(biāo)記的長(zhǎng)度”沒(méi)超過(guò)“標(biāo)記上限(readAheadLimit)”,并且“標(biāo)記上限(readAheadLimit)”小于/等于“緩沖的長(zhǎng)度”;
執(zhí)行流程如下,
(01) 其它函數(shù)調(diào)用 fill(),來(lái)更新緩沖區(qū)的數(shù)據(jù)
(02) fill() 執(zhí)行代碼 if (readAheadLimit <= cb.length) { ... }
為了方便分析,我們將這種情況下fill()執(zhí)行的操作等價(jià)于以下代碼:
private void fill() throws IOException {
int dst;
if (markedChar > UNMARKED) {
int delta = nextChar - markedChar;
if ((delta < readAheadLimit) && (readAheadLimit <= cb.length) ) {
System.arraycopy(cb, markedChar, cb, 0, delta);
markedChar = 0;
dst = delta;
nextChar = nChars = delta;
}
}
int n;
do {
n = in.read(cb, dst, cb.length - dst);
} while (n == 0);
if (n > 0) {
nChars = dst + n;
nextChar = dst;
}
}
說(shuō)明:
這種情況發(fā)生的情況是 — — BufferedReader中有很長(zhǎng)的數(shù)據(jù),我們每次從中讀取一部分?jǐn)?shù)據(jù)到緩沖區(qū)中進(jìn)行操作。當(dāng)我們讀取完緩沖區(qū)中的數(shù)據(jù)之后,并且此時(shí),BufferedReader存在標(biāo)記時(shí),同時(shí),“當(dāng)前標(biāo)記的長(zhǎng)度”小于“標(biāo)記上限”,并且“標(biāo)記上限”小于/等于“緩沖區(qū)長(zhǎng)度”;那么,就發(fā)生情況3。此時(shí),我們保留“被標(biāo)記的位置”(即,保留被標(biāo)記位置開(kāi)始的數(shù)據(jù)),并更新緩沖區(qū)(將新增的數(shù)據(jù),追加到保留的數(shù)據(jù)之后)。
情況4:讀取完緩沖區(qū)的數(shù)據(jù),緩沖區(qū)的標(biāo)記位置>0,“當(dāng)前標(biāo)記的長(zhǎng)度”沒(méi)超過(guò)“標(biāo)記上限(readAheadLimit)”,并且“標(biāo)記上限(readAheadLimit)”大于“緩沖的長(zhǎng)度”;
執(zhí)行流程如下,
(01) 其它函數(shù)調(diào)用 fill(),來(lái)更新緩沖區(qū)的數(shù)據(jù)
(02) fill() 執(zhí)行代碼 else { char ncb[] = new char[readAheadLimit]; ... }
為了方便分析,我們將這種情況下fill()執(zhí)行的操作等價(jià)于以下代碼:
private void fill() throws IOException {
int dst;
if (markedChar > UNMARKED) {
int delta = nextChar - markedChar;
if ((delta < readAheadLimit) && (readAheadLimit > cb.length) ) {
char ncb[] = new char[readAheadLimit];
System.arraycopy(cb, markedChar, ncb, 0, delta);
cb = ncb;
markedChar = 0;
dst = delta;
nextChar = nChars = delta;
}
}
int n;
do {
n = in.read(cb, dst, cb.length - dst);
} while (n == );
if (n > ) {
nChars = dst + n;
nextChar = dst;
}
}
說(shuō)明:
這種情況發(fā)生的情況是 — — BufferedReader中有很長(zhǎng)的數(shù)據(jù),我們每次從中讀取一部分?jǐn)?shù)據(jù)到緩沖區(qū)中進(jìn)行操作。當(dāng)我們讀取完緩沖區(qū)中的數(shù)據(jù)之后,并且此時(shí),BufferedReader存在標(biāo)記時(shí),同時(shí),“當(dāng)前標(biāo)記的長(zhǎng)度”小于“標(biāo)記上限”,并且“標(biāo)記上限”大于“緩沖區(qū)長(zhǎng)度”;那么,就發(fā)生情況4。此時(shí),我們要先更新緩沖區(qū)的大小,然后再保留“被標(biāo)記的位置”(即,保留被標(biāo)記位置開(kāi)始的數(shù)據(jù)),并更新緩沖區(qū)數(shù)據(jù)(將新增的數(shù)據(jù),追加到保留的數(shù)據(jù)之后)。
示例代碼
關(guān)于BufferedReader中API的詳細(xì)用法,參考示例代碼(BufferedReaderTest.java):
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.FileNotFoundException;
import java.lang.SecurityException;
/**
* BufferedReader 測(cè)試程序
*
*
*/
public class BufferedReaderTest {
private static final int LEN = 5;
public static void main(String[] args) {
testBufferedReader() ;
}
/**
* BufferedReader的API測(cè)試函數(shù)
*/
private static void testBufferedReader() {
// 創(chuàng)建BufferedReader字符流,內(nèi)容是ArrayLetters數(shù)組
try {
File file = new File("bufferedreader.txt");
BufferedReader in =
new BufferedReader(
new FileReader(file));
// 從字符流中讀取5個(gè)字符。“abcde”
for (int i=0; i<LEN; i++) {
// 若能繼續(xù)讀取下一個(gè)字符,則讀取下一個(gè)字符
if (in.ready()) {
// 讀取“字符流的下一個(gè)字符”
int tmp = in.read();
System.out.printf("%d : %c\n", i, tmp);
}
}
// 若“該字符流”不支持標(biāo)記功能,則直接退出
if (!in.markSupported()) {
System.out.println("make not supported!");
return ;
}
// 標(biāo)記“當(dāng)前索引位置”,即標(biāo)記第6個(gè)位置的元素--“f”
// 1024對(duì)應(yīng)marklimit
in.mark(1024);
// 跳過(guò)22個(gè)字符。
in.skip(22);
// 讀取5個(gè)字符
char[] buf = new char[LEN];
in.read(buf, 0, LEN);
System.out.printf("buf=%s\n", String.valueOf(buf));
// 讀取該行剩余的數(shù)據(jù)
System.out.printf("readLine=%s\n", in.readLine());
// 重置“輸入流的索引”為mark()所標(biāo)記的位置,即重置到“f”處。
in.reset();
// 從“重置后的字符流”中讀取5個(gè)字符到buf中。即讀取“fghij”
in.read(buf, , LEN);
System.out.printf("buf=%s\n", String.valueOf(buf));
in.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
程序中讀取的bufferedreader.txt的內(nèi)容如下:
abcdefghijklmnopqrstuvwxyz 0123456789 ABCDEFGHIJKLMNOPQRSTUVWXYZ
運(yùn)行結(jié)果:
0 : a 1 : b 2 : c 3 : d 4 : e buf=01234 readLine=56789 buf=fghij
以上所述是小編給大家介紹的Java 中的 BufferedReader 介紹_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理,希望對(duì)大家有所幫助,如果大家有任何疑問(wèn)請(qǐng)給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對(duì)腳本之家網(wǎng)站的支持!
相關(guān)文章
實(shí)例講解JAVA設(shè)計(jì)模式之備忘錄模式
這篇文章主要介紹了JAVA設(shè)計(jì)模式之備忘錄模式的的相關(guān)資料,文中示例代碼非常詳細(xì),供大家參考和學(xué)習(xí),感興趣的朋友可以了解下2020-06-06
Flutter ListView 上拉加載更多下拉刷新功能實(shí)現(xiàn)方法
這篇文章主要介紹了Flutter ListView 上拉加載更多下拉刷新功能實(shí)現(xiàn)方法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2019-07-07
KafkaListener注解的實(shí)現(xiàn)機(jī)制源碼解析
這篇文章主要為大家介紹了KafkaListener注解的實(shí)現(xiàn)機(jī)制源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10
Java中Scanner類與BufferReader類的不同點(diǎn)(非常詳細(xì))
這篇文章主要介紹了Java中Scanner類與BufferReader類的不同點(diǎn)(非常詳細(xì))的相關(guān)資料,需要的朋友可以參考下2016-08-08
Java 高并發(fā)二:多線程基礎(chǔ)詳細(xì)介紹
本文主要介紹Java 高并發(fā)多線程的知識(shí),這里整理詳細(xì)的資料來(lái)解釋線程的知識(shí),有需要的學(xué)習(xí)高并發(fā)的朋友可以參考下2016-09-09
java密鑰交換算法DH定義與應(yīng)用實(shí)例分析
這篇文章主要介紹了java密鑰交換算法DH定義與應(yīng)用,結(jié)合實(shí)例形式分析了Java密鑰交換算法DH的原理、定義、使用方法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下2019-09-09
java構(gòu)造器的重載實(shí)現(xiàn)實(shí)例講解
在本篇文章里小編給大家整理的是一篇關(guān)于java構(gòu)造器的重載實(shí)現(xiàn)實(shí)例講解內(nèi)容,有興趣的朋友們可以學(xué)習(xí)下。2021-01-01
Spark SQL關(guān)于性能調(diào)優(yōu)選項(xiàng)詳解
這篇文章將為大家詳細(xì)講解有關(guān)Spark SQL性能調(diào)優(yōu)選項(xiàng),小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲2023-02-02

