java字符流处理之while readline

BufferedReader的readLine()方法是阻塞式的, 如果到达流末尾, 就返回null, 但如果client的socket末经关闭就销毁, 则会产生IO异常. 正常的方法就是使用socket.close()关闭不需要的socket.

从一个有若干行的文件中依次读取各行,处理后输出,如果用以下方法,则会出现除第一行外行首字符丢失现象

String str  = null;
br=new BufferedReader(new FileReader(fileName));
do{
  str = buf.readLine()); 
}while(br.read()!=-1);
以下用法会使每行都少首字符
while(br.read() != -1){
       str = br.readLine();     
 }
原因就在于br.read() != -1 这判断条件上。 因为在执行这个条件的时候其实它已经读取了一个字符了,然而在这里并没有对读取出来的这个字符做处理,所以会出现少一个字符,如果你这里写的是while(br.readLine()!=null)会出现隔一行少一行!

建议使用以下方法
String str = null;
      while((str = br.readLine()) != null){
      //System.out.println(str);//此时str就保存了一行字符串
}

这样应该就可以无字符丢失地得到一行了

虽然写IO方面的程序不多,但BufferedReader/BufferedInputStream倒是用过好几次的,原因是:

  • 它有一个很特别的方法:readLine(),使用起来特别方便,每次读回来的都是一行,省了很多手动拼接buffer的琐碎;
  • 它比较高效,相对于一个字符/字节地读取、转换、返回来说,它有一个缓冲区,读满缓冲区才返回;一般情况下,都建议使用它们把其它Reader/InputStream包起来,使得读取数据更高效。
  • 对于文件来说,经常遇到一行一行的,特别相符情景。

这次是在蓝牙开发时,使用两个蓝牙互相传数据(即一个发一个收),bluecove这个开源组件已经把数据读取都封装成InputStream了,也就相当于平时的IO读取了,很自然就使用起readLine()来了。

 

发数据:

[java] view plaincopy

  1. BufferedWriter output = new BufferedWriter(new OutputStreamWriter(conn.openOutputStream()));   
  2. int i = 1;  
  3. String message = "message " + i;  
  4. while(isRunning) {  
  5.     output.write(message+"/n");   
  6.     i++;  
  7. }  

 

 

读数据:

[java] view plaincopy

  1. BufferedReader input = new BufferedReader(new  InputStreamReader(m_conn.openInputStream()));  
  2. String message = "";  
  3. String line = null;  
  4. while((line = m_input.readLine()) != null) {  
  5.     message += line;  
  6. }  
  7. System.out.println(message);  

 

 

上面是代码的节选,使用这段代码会发现写数据时每次都成功,而读数据侧却一直没有数据输出(除非把流关掉)。经过折腾,原来这里面有几个大问题需要理解:

  • 误以为readLine()是读取到没有数据时就返回null(因为其它read方法当读到没有数据时返回-1),而实际上readLine()是一个阻塞函数,当没有数据读取时,就一直会阻塞在那,而不是返回null;因为readLine()阻塞后,System.out.println(message)这句根本就不会执行到,所以在接收端就不会有东西输出。要想执行到System.out.println(message),一个办法是发送完数据后就关掉流,这样readLine()结束阻塞状态,而能够得到正确的结果,但显然不能传一行就关一次数据流;另外一个办法是把System.out.println(message)放到while循环体内就可以。
  • readLine()只有在数据流发生异常或者另一端被close()掉时,才会返回null值。
  • 如果不指定buffer大小,则readLine()使用的buffer有8192个字符。在达到buffer大小之前,只有遇到"/r"、"/n"、"/r/n"才会返回。

readLine()的实质(下面是从JDK源码摘出来的):

[java] view plaincopy

  1. String readLine(boolean ignoreLF) throws IOException {  
  2.     StringBuffer s = null;  
  3.     int startChar;  
  4.         synchronized (lock) {  
  5.             ensureOpen();  
  6.         boolean omitLF = ignoreLF || skipLF;  
  7.         bufferLoop:  
  8.         for (;;) {  
  9.         if (nextChar >= nChars)  
  10.             fill(); //在此读数据  
  11.         if (nextChar >= nChars) { /* EOF */  
  12.             if (s != null && s.length() > 0)  
  13.             return s.toString();  
  14.             else  
  15.             return null;  
  16.         }  
  17.       ......//其它  
  18. }  
  19.   
  20. private void fill() throws IOException {  
  21.     ..../其它  
  22.     int n;  
  23.     do {  
  24.         n = in.read(cb, dst, cb.length - dst); //实质  
  25.     } while (n == 0);  
  26.     if (n > 0) {  
  27.         nChars = dst + n;  
  28.         nextChar = dst;  
  29.     }  
  30.     }  

从上面看出,readLine()是调用了read(char[] cbuf, int off, int len) 来读取数据,后面再根据"/r"或"/n"来进行数据处理。

 

在Java I/O书上也说了:

public String readLine() throws IOException
This method returns a string that contains a line of text from a text file. /r, /n, and /r/n are assumed to be line breaks and are not included in the returned string. This method is often used when reading user input from System.in, since most platforms only send the user's input to the running program after the user has typed a full line (that is, hit the Return key).
readLine() has the same problem with line ends that DataInputStream's readLine() method has; that is, the potential to hang on a lone carriage return that ends the stream . This problem is especially acute on networked connections, where readLine() should never be used.

 

小结,使用readLine()一定要注意:

  1. 读入的数据要注意有/r或/n或/r/n
  2. 没有数据时会阻塞,在数据流异常或断开时才会返回null
  3. 使用socket之类的数据流时,要避免使用readLine(),以免为了等待一个换行/回车符而一直阻塞

以前学习的时候也没有太在意,在项目中使用到了才发现呵呵

1.读取一个txt文件,方法很多种我使用了字符流来读取(为了方便)

 

  FileReader fr = new FileReader("f:\\TestJava.java");
   BufferedReader bf = new BufferedReader(fr);

//这里进行读取

int b;
   while((b=bf.read())!=-1){
    System.out.println(bf.readLine());
   }

发现每行的第一个字符都没有显示出来,原因呢:b=bf.read())!=-1  每次都会先读取一个字节出来,所以后面的bf.readLine());
读取的就是每行少一个字节

所以,应该使用

String valueString = null;
   while ((valueString=bf.readLine())!=null){
    
    
    System.out.println(valueString);
   }

时间: 2024-10-25 06:54:10

java字符流处理之while readline的相关文章

Java字符流与字节流区别与用法分析_java

本文实例讲述了Java字符流与字节流区别与用法.分享给大家供大家参考,具体如下: 字节流与字符流主要的区别是他们的的处理方式 流分类: 1.Java的字节流 InputStream是所有字节输入流的祖先,而OutputStream是所有字节输出流的祖先. 2.Java的字符流 Reader是所有读取字符串输入流的祖先,而writer是所有输出字符串的祖先. InputStream,OutputStream,Reader,writer都是抽象类.所以不能直接new 字节流是最基本的,所有的Inpu

Java字符流和字节流对文件操作的区别_java

记得当初自己刚开始学习Java的时候,对Java的IO流这一块特别不明白,所以写了这篇随笔希望能对刚开始学习Java的人有所帮助,也方便以后自己查询.Java的IO流分为字符流(Reader,Writer)和字节流(InputStream,OutputStream),字节流顾名思义字节流就是将文件的内容读取到字节数组,然后再输出到另一个文件中.而字符流操作的最小单位则是字符.可以先看一下IO流的概述:   下面首先是通过字符流对文件进行读取和写入: package lib; import jav

java字符流

网上有很多地方说inputStreamReader和outStreamWriter.BufferedReader和BufferedWriter都是字符流.不过也有地方说inputStreamReader和outStreamWriter只是转换流,实现字节流到字符流的转换. 而在我看来,两种说法都有道理,如果一定要分个高下的话,那就更加趋向于认同前一种. 因为只要和FileInputStream做一个简单的比较就可以知道inputSteamReader是按字符读取的,而FileInputStrea

java 字符流-java 封装流关闭的疑问

问题描述 java 封装流关闭的疑问 BufferedWriter writer = null; try { writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filePath), "UTF-8")); writer.write(" " + context); writer.flush(); logger.debug("写文件成功,[filePath="

JAVA之旅(二十五)——文件复制,字符流的缓冲区,BufferedWriter,BufferedReader,通过缓冲区复制文件,readLine工作原理,自定义readLine

JAVA之旅(二十五)--文件复制,字符流的缓冲区,BufferedWriter,BufferedReader,通过缓冲区复制文件,readLine工作原理,自定义readLine 我们继续IO上个篇幅讲 一.文本复制 读写都说了,我们来看下其他的操作,我们首先来看复制 复制原理:其实就是将C盘下的文件数据存储到D盘的一个文件中 实现的步骤: 1.在D盘创建一个文件,用于存储文件中的数据 2.定义读取流和文件关联 3.通过不断的读写完成数据的存储 关闭资源 package com.lgl.hel

java IO之 字符流 (字符流 = 字节流 + 编码表) 装饰器模式

字符流 计算机并不区分二进制文件与文本文件.所有的文件都是以二进制形式来存储的,因此, 从本质上说,所有的文件都是二进制文件.所以字符流是建立在字节流之上的,它能够提供字符 层次的编码和解码.列如,在写入一个字符时,Java虚拟机会将字符转为文件指定的编码(默认 是系统默认编码),在读取字符时,再将文件指定的编码转化为字符. 常见的码表如下: ASCII:           美国标准信息交换码.用一个字节的7位可以表示. ISO8859-1:   拉丁码表.欧洲码表,用一个字节的8位表示.又称

java笔记八:IO流之字符流与字符缓冲流

java中字符流主要都是继承于Reader和Writer两个抽象类.用于对字符文本的读写操作.   一.转换类流 1 package com.iotest; 2 3 import java.io.FileInputStream; 4 import java.io.FileNotFoundException; 5 import java.io.FileOutputStream; 6 import java.io.IOException; 7 import java.io.InputStreamRe

Java基础-21总结字符流,IO流编码问题,实用案例必做一遍

你需要的是什么,直接评论留言. 获取更多资源加微信公众号"Java帮帮" (是公众号,不是微信好友哦) 还有"Java帮帮"今日头条号,技术文章与新闻,每日更新,欢迎阅读 学习交流请加Java帮帮交流QQ群553841695 分享是一种美德,分享更快乐! 1:字符流(掌握)  // 字节流读取中文可能出现的小问题(所以用字符流输入输出中文) package cn.itcast_01; import java.io.FileInputStream; import ja

Java编程中字节流与字符流IO操作示例_java

 IO流基本概念IO流用来处理设备之间的数据传输 Java对数据的操作是通过流的方式 Java用于操作流的对象都是在IO包上 流按操作数据分为两种:字节流和字符流 流按流向分为:输入流,输出流. 字节流的抽象基类:InputStream,OutputStream 字符流的抽象基类:Reader,Writer 注:由这4个类派生出来的子类名称都是以其父类名作为子类名的后缀. 如:InputStream的子类:FileInputStream 如:Reader的子类FileReader 如创建一个Fi