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

 更新时间:2021年12月09日 14:18:32   作者:不爱吃汤圆的汤圆坨坨  
这篇文章主要介绍了bufferedreader的read()与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);
		    }
	        }
	    }

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • java实现文件压缩成zip的工具类

    java实现文件压缩成zip的工具类

    这篇文章主要为大家详细介绍了java实现文件压缩成zip的工具类,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-07-07
  • MyBatis 多表联合查询及优化方法

    MyBatis 多表联合查询及优化方法

    大家都知道Hibernate 是全自动的数据库持久层框架,它可以通过实体来映射数据库,通过设置一对多、多对一、一对一、多对多的关联来实现联合查询,接下来通过本文给大家介绍MyBatis 多表联合查询及优化,需要的朋友可以参考下
    2022-08-08
  • Oracle + Mybatis实现批量插入、更新和删除示例代码

    Oracle + Mybatis实现批量插入、更新和删除示例代码

    利用MyBatis动态SQL的特性,我们可以做一些批量的操作,下面这篇文章主要给大家介绍了关于Oracle + Mybatis实现批量插入、更新和删除的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面来一起看看吧。
    2018-01-01
  • 图解Java排序算法之堆排序

    图解Java排序算法之堆排序

    这篇文章主要为大家详细介绍了Java经典排序算法之堆排序,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11
  • MyBatis多对多映射初识教程

    MyBatis多对多映射初识教程

    这篇文章重点给大家介绍mybatis多对多映射,多对多映射的例子也很常见,本文通过代码实例相结合的方式给大家介绍mybatis多对多映射,需要的朋友参考下吧
    2016-08-08
  • 详解Maven POM(项目对象模型)

    详解Maven POM(项目对象模型)

    这篇文章主要介绍了Maven POM(项目对象模型)的相关资料,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-07-07
  • java list和map切割分段的实现及多线程应用案例

    java list和map切割分段的实现及多线程应用案例

    这篇文章主要为大家介绍了java list和map切割分段的实现及多线程应用案例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-12-12
  • JDK21无法导入TimeUnit类的解决办法

    JDK21无法导入TimeUnit类的解决办法

    这篇文章主要给大家介绍了关于JDK21无法导入TimeUnit类的解决办法,TimeUnit是java.util.concurrent包下面的一个类,TimeUnit提供了可读性更好的线程暂停操作,通常用来替换Thread.sleep(),需要的朋友可以参考下
    2024-01-01
  • spring boot集成p6spy的最佳实践

    spring boot集成p6spy的最佳实践

    这篇文章主要介绍了spring boot集成p6spy的最佳实践-p6spy-spring-boot-starter的项目案例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2022-02-02
  • 关于使用swagger整合springMVC的方法

    关于使用swagger整合springMVC的方法

    在平时开发写接口文档的工作时,一般都是word文档,带来书写麻烦、维护麻烦的问题,比如改了源代码忘了更新文档、解释不明确带来歧义、无法在线尝试等等,swagger可以有效解决这类问题,需要的朋友可以参考下
    2023-04-04

最新评论