基于bufferedreader的read()与readline()读取出错原因及解决

网友投稿 1282 2022-11-16

基于bufferedreader的read()与readline()读取出错原因及解决

基于bufferedreader的read()与readline()读取出错原因及解决

目录bufferedreader的read()与readline()读取出错bufferedReader中的readLine()源码解析

bufferedreader的read()与readline()读取出错

以前学习java的时候也没有太在意,直到最近做项目时使用了才发现这个问题,总是第一个字符输不出来

bufferedreader这个类借用别人的话来说,就是一个包装类

它可以包装字符流,将字符流放入缓存里,先把字符读到缓存里,到缓存满了或者你flush的时候,再读入内存,就是为了提高读的效率而设计的。

读取一个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());

}

发现每行的第一个字符都没有显示出来,后来发现 c=br.read())!=-1 每次都会先读取一个字节出来,所以后面的br.readLine());

读取的就是每行少一个字节

所以,应该使用

String input = null;

while ((input=br.readLine())!=null){undefined

System.out.println(input);

}

这样就能解决了~

bufferedReader中的readLine()源码解析

String readLine(boolean ignoreLF) throws IOException {

//行(hang)数据的缓冲s

StringBuffer s = null;

int startChar;

synchronized (lock) {

/*确保被bufferedReader包装的输入流没有关闭*/

ensureOpen();

/* 如果 读到'\r',skipLF置为true,

* 这是skip()方法里面的部分代码,它展示了通过skipLF来忽略'\n'

* if (skipLF) {

skipLF = false;

if (cb[nextChar] == '\n') {

nextChar++;

}

}

*ignoreLF一直就是false

**/

boolean omitLF = ignoreLF || skipLF;

/* bufferLoop主要是不断地遍历底层的数组cb,并取两个换行符之间的数据付给行缓冲s。当底层数组遍历完要用fill()把数据从流中填充到cb,直到流的末尾

*charloop,主要是遍历缓冲数组cb,以确定'\n','\r'的位置

nextChar:下次读取缓冲字符数组cb的位置,

nChars:缓冲字符数组cb的length

*/

bufferLoop:

for (;;) {

//1、如果缓冲数组的数据不足,或者已经读到了数组的末尾时:

//1.1如果下次读取的位置已经到了or超过数组的长度,从流中读数据到缓冲数组cb中

if (nextChar >= nChars)

fill();

/*1.2如果从流中读数据到数组cb之后, nextChar,nChars的大小关系没有改变.

说明到了文件的末尾,END OF FILE.返回s

*/

if (nextChar >= nChars) { /* EOF */

if (s != null && s.length() > 0)

return s.toString();

else

return null;

}

//2 缓冲数组中有足够的数据时:

/*从本个换行符所在的索引位置开始,遍历char [] cb ,直到找到\n \r,把两个换行符之间的字符序列填充进s

*eol:END OF LINE

*类属性char [] cb ,也就是bufferReader类的缓冲数组。length由构造器指定,若不指定默认为8 * 1024 = 8192,与内存页大小密切相关

* */

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);

}

}

}

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:关于 Angular 应用 Module 的 forRoot 方法的讨论
下一篇:mysql用in走索引吗?(mysql-8.0.21、5.5.40是不一样的)实践出真知——看完就要注意in的用法了
相关文章

 发表评论

暂时没有评论,来抢沙发吧~