基于bufferedreader的read()與readline()讀取出錯原因及解決
bufferedreader的read()與readline()讀取出錯
以前學(xué)習(xí)java的時候也沒有太在意,直到最近做項目時使用了才發(fā)現(xiàn)這個問題,總是第一個字符輸不出來
bufferedreader這個類借用別人的話來說,就是一個包裝類
它可以包裝字符流,將字符流放入緩存里,先把字符讀到緩存里,到緩存滿了或者你flush的時候,再讀入內(nèi)存,就是為了提高讀的效率而設(shè)計的。
讀取一個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)每行的第一個字符都沒有顯示出來,后來發(fā)現(xiàn) c=br.read())!=-1 每次都會先讀取一個字節(jié)出來,所以后面的br.readLine());
讀取的就是每行少一個字節(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,并取兩個換行符之間的數(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ù)組的末尾時:
//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ù)時:
/*從本個換行符所在的索引位置開始,遍歷char [] cb ,直到找到\n \r,把兩個換行符之間的字符序列填充進s
*eol:END OF LINE
*類屬性char [] cb ,也就是bufferReader類的緩沖數(shù)組。length由構(gòu)造器指定,若不指定默認為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找到換行符后,從上個換行符到本換行符之間的序列,填充給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至少遍歷到一次換行符時*/
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,從上個換行符到最后
s.append(cb, startChar, i - startChar);
}
}
}
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
MyBatis?多表聯(lián)合查詢及優(yōu)化方法
大家都知道Hibernate 是全自動的數(shù)據(jù)庫持久層框架,它可以通過實體來映射數(shù)據(jù)庫,通過設(shè)置一對多、多對一、一對一、多對多的關(guān)聯(lián)來實現(xiàn)聯(lián)合查詢,接下來通過本文給大家介紹MyBatis?多表聯(lián)合查詢及優(yōu)化,需要的朋友可以參考下2022-08-08
Oracle + Mybatis實現(xiàn)批量插入、更新和刪除示例代碼
利用MyBatis動態(tài)SQL的特性,我們可以做一些批量的操作,下面這篇文章主要給大家介紹了關(guān)于Oracle + Mybatis實現(xiàn)批量插入、更新和刪除的相關(guān)資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒,下面來一起看看吧。2018-01-01
java?list和map切割分段的實現(xiàn)及多線程應(yīng)用案例
這篇文章主要為大家介紹了java?list和map切割分段的實現(xiàn)及多線程應(yīng)用案例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12
關(guān)于使用swagger整合springMVC的方法
在平時開發(fā)寫接口文檔的工作時,一般都是word文檔,帶來書寫麻煩、維護麻煩的問題,比如改了源代碼忘了更新文檔、解釋不明確帶來歧義、無法在線嘗試等等,swagger可以有效解決這類問題,需要的朋友可以參考下2023-04-04

