基于bufferedreader的read()與readline()讀取出錯(cuò)原因及解決
bufferedreader的read()與readline()讀取出錯(cuò)
以前學(xué)習(xí)java的時(shí)候也沒有太在意,直到最近做項(xiàng)目時(shí)使用了才發(fā)現(xiàn)這個(gè)問題,總是第一個(gè)字符輸不出來
bufferedreader這個(gè)類借用別人的話來說,就是一個(gè)包裝類
它可以包裝字符流,將字符流放入緩存里,先把字符讀到緩存里,到緩存滿了或者你flush的時(shí)候,再讀入內(nèi)存,就是為了提高讀的效率而設(shè)計(jì)的。
讀取一個(gè)txt文件,方法很多種而我使用的是字符流來讀取
int c;
FileReader file = new FileReader("D:\\emDemo.java");
BufferedReader br = new BufferedReader(file);
while((c=br.read())!=-1){undefined
System.out.println(br.readLine());
}
發(fā)現(xiàn)每行的第一個(gè)字符都沒有顯示出來,后來發(fā)現(xiàn) c=br.read())!=-1 每次都會(huì)先讀取一個(gè)字節(jié)出來,所以后面的br.readLine());
讀取的就是每行少一個(gè)字節(jié)
所以,應(yīng)該使用
String input = null;
while ((input=br.readLine())!=null){undefined
System.out.println(input);
}
這樣就能解決了~
bufferedReader中的readLine()源碼解析
String readLine(boolean ignoreLF) throws IOException {
//行(hang)數(shù)據(jù)的緩沖s
StringBuffer s = null;
int startChar;
synchronized (lock) {
/*確保被bufferedReader包裝的輸入流沒有關(guān)閉*/
ensureOpen();
/* 如果 讀到'\r',skipLF置為true,
* 這是skip()方法里面的部分代碼,它展示了通過skipLF來忽略'\n'
* if (skipLF) {
skipLF = false;
if (cb[nextChar] == '\n') {
nextChar++;
}
}
*ignoreLF一直就是false
**/
boolean omitLF = ignoreLF || skipLF;
/* bufferLoop主要是不斷地遍歷底層的數(shù)組cb,并取兩個(gè)換行符之間的數(shù)據(jù)付給行緩沖s。當(dāng)?shù)讓訑?shù)組遍歷完要用fill()把數(shù)據(jù)從流中填充到cb,直到流的末尾
*charloop,主要是遍歷緩沖數(shù)組cb,以確定'\n','\r'的位置
nextChar:下次讀取緩沖字符數(shù)組cb的位置,
nChars:緩沖字符數(shù)組cb的length
*/
bufferLoop:
for (;;) {
//1、如果緩沖數(shù)組的數(shù)據(jù)不足,或者已經(jīng)讀到了數(shù)組的末尾時(shí):
//1.1如果下次讀取的位置已經(jīng)到了or超過數(shù)組的長度,從流中讀數(shù)據(jù)到緩沖數(shù)組cb中
if (nextChar >= nChars)
fill();
/*1.2如果從流中讀數(shù)據(jù)到數(shù)組cb之后, nextChar,nChars的大小關(guān)系沒有改變.
說明到了文件的末尾,END OF FILE.返回s
*/
if (nextChar >= nChars) { /* EOF */
if (s != null && s.length() > 0)
return s.toString();
else
return null;
}
//2 緩沖數(shù)組中有足夠的數(shù)據(jù)時(shí):
/*從本個(gè)換行符所在的索引位置開始,遍歷char [] cb ,直到找到\n \r,把兩個(gè)換行符之間的字符序列填充進(jìn)s
*eol:END OF LINE
*類屬性char [] cb ,也就是bufferReader類的緩沖數(shù)組。length由構(gòu)造器指定,若不指定默認(rèn)為8 * 1024 = 8192,與內(nèi)存頁大小密切相關(guān)
* */
boolean eol = false;
char c = 0;
int i;
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;
}
}
/*2.1找到換行符后,從上個(gè)換行符到本換行符之間的序列,填充給s*/
startChar = nextChar;
nextChar = i;
if (eol) {
String str;
/*2.1.1如果是第一次遍歷到換行符,*/
if (s == null)
{
str = new String(cb, startChar, i - startChar);
}
/*2.1.2至少遍歷到一次換行符時(shí)*/
else
{
s.append(cb, startChar, i - startChar);
str = s.toString();
}
//更新下次讀取的位置
nextChar++;
if (c == '\r') {
skipLF = true;
}
return str;
}
//2.2如果沒有換行符
if (s == null)
//類屬性int defaultExpectedLineLength = 80
s = new StringBuffer(defaultExpectedLineLength);
//填充s,從上個(gè)換行符到最后
s.append(cb, startChar, i - startChar);
}
}
}
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
淺析Spring配置中的classpath:與classpath*:的區(qū)別
這篇文章主要介紹了Spring配置中的"classpath:"與"classpath*:"的區(qū)別,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08
Flutter驗(yàn)證碼輸入框的2種方法實(shí)現(xiàn)
本文主要介紹了Flutter驗(yàn)證碼輸入框的2種方法實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-12-12
Java設(shè)計(jì)模式之原型模式詳細(xì)解讀
這篇文章主要介紹了Java設(shè)計(jì)模式之原型模式詳細(xì)解讀,原型模式屬于創(chuàng)建型設(shè)計(jì)模式,用于創(chuàng)建重復(fù)的對象,且同時(shí)又保證了性能,該設(shè)計(jì)模式的好處是將對象的創(chuàng)建與調(diào)用方分離,需要的朋友可以參考下2023-12-12
Mybatis-config.xml中映射Mapper.xml文件遇到的錯(cuò)誤及解決
這篇文章主要介紹了Mybatis-config.xml中映射Mapper.xml文件遇到的錯(cuò)誤及解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-06-06

