原文

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

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

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

发数据:

  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. }

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

读数据:

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

BufferedReader input = new BufferedReader(new InputStreamReader(m_conn.openInputStream()));
String message = "";
String line = null;
while((line = m_input.readLine()) != null) {
message += line;
}
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源码摘出来的):

  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. private void fill() throws IOException {
  20. ..../其它
  21. int n;
  22. do {
  23. n = in.read(cb, dst, cb.length - dst); //实质
  24. } while (n == 0);
  25. if (n > 0) {
  26. nChars = dst + n;
  27. nextChar = dst;
  28. }
  29. }

String readLine(boolean ignoreLF) throws IOException {
StringBuffer s = null;
int startChar;
synchronized (lock) {
ensureOpen();
boolean omitLF = ignoreLF || skipLF;
bufferLoop:
for (;;) {
if (nextChar >= nChars)
fill(); //在此读数据
if (nextChar >= nChars) { /* EOF */
if (s != null && s.length() > 0)
return s.toString();
else
return null;
}
......//其它
}

private void fill() throws IOException {
..../其它
int n;
do {
n = in.read(cb, dst, cb.length - dst); //实质
} while (n == 0);
if (n > 0) {
nChars = dst + n;
nextChar = dst;
}
}

从上面看出,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(),以免为了等待一个换行/回车符而一直阻塞

java readLine()的更多相关文章

  1. Spark案例分析

    一.需求:计算网页访问量前三名 import org.apache.spark.rdd.RDD import org.apache.spark.{SparkConf, SparkContext} /* ...

  2. java中readLine()方法为什么有的行读不到?

    今天在使用java对IO操作时,readLine()输出到控制台的行少了很多.后来发现readLine()实际上是一次读取一行.如果我们不话readLine()读取的行内容赋给一个字符串的话,每直接调 ...

  3. Java中的BufferedReader 的readLine方法

    import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.FileReader; import java ...

  4. Java Socket 使用BufferedWriter和BufferedReader要注意readLine 以及换行标志的发送

    当接收的类使用的是BufferedReader,发送的类是BufferedWriter的时候,要注意发送的一行要有换行标识符. 请看下面一个例子,服务器接收不到客户端的信息. 服务器: import ...

  5. Java基础知识强化之IO流笔记53:IO流练习之 自定义类模拟BufferedReader的readLine()功能案例

    1. 用Reader模拟BufferedReader的readLine()功能:   readLine():一次读取一行,根据换行符判断是否结束,只返回内容,不返回换行符 2. 代码实现和思路分析: ...

  6. Java基础知识强化之IO流笔记41:字符流缓冲流之复制文本文件案例02(使用 [ newLine() / readLine() ] )(重要)

    1. 使用字符流缓冲流的特殊功能 [ newLine() / readLine() ] 需求:把当前项目目录下的a.txt内容复制到当前项目目录下的b.txt中  数据源: a.txt -- 读取数据 ...

  7. Java基础知识强化之IO流笔记40:字符流缓冲流之特殊功能 [ newLine() / readLine() ]

    1. 字符缓冲流的特殊方法 BufferedWriter: public void newLine():根据系统来决定换行符 BufferedReader: public String readLin ...

  8. Java:java中BufferedReader的read()及readLine()方法的使用心得

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

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

    JAVA之旅(二十五)--文件复制,字符流的缓冲区,BufferedWriter,BufferedReader,通过缓冲区复制文件,readLine工作原理,自定义readLine 我们继续IO上个篇 ...

随机推荐

  1. Xib与View关联方法

    1,在需要实例的地方 //加载一个uiview的作法 [LotteryInvestigationView *lotteryInvestigationView=[[[NSBundle mainBundl ...

  2. log4net.config 单独文件

    使用的命名空间下添加 [assembly: log4net.Config.DOMConfigurator(ConfigFile = "log4net.config", Watch ...

  3. MFC学习笔记(一)向模态对话框传递数据

    声明构造函数为2个参数,具有默认参数的参数须放在后面. CDialogDimmer::CDialogDimmer(CString name,CWnd* pParent /*=NULL*/) : CDi ...

  4. 持续集成-sourcetree的安装、使用记录

    1.参考 http://blog.sina.com.cn/s/blog_672143a30102vold.html 2.问题-安装sourcetree后,打开时提示下载但是连接不上相应链接 自行下载g ...

  5. How To Use Hbase Bulk Loading

    最近在学习hbase,学到利用如何将数据导入到hbase中,采用的方式是批量导入:bulk load的方法,中间出现了一些问题,下面将执行的步骤记录一下,以供日后查阅: 说明:导入的方式是将csv文件 ...

  6. .net 后台读取pdf的值

    在网上找了内容 下载了这个插件 引用在了项目中 然后找到pdf中的位置 进行读取 string pdfPath = Server.MapPath("~/ViewPatPdf.pdf" ...

  7. android sdk 更新用的HOSTS

    74.125.113.121 developer.android.com203.208.46.146 www.google.com 203.208.46.146 dl.google.com 203.2 ...

  8. 帐户当前被锁定,所以用户 sa 登录失败。系统管理员无法将该帐户解锁 解决方法

    ALTER LOGIN sa ENABLE ; GO ALTER LOGIN sa WITH PASSWORD = 'password' unlock, check_policy = off, che ...

  9. 模版页面通过get传参数http://.../good_id/2;控制中可以直接使用echo $good_id;//2

  10. 如何把TOMCAT 添加到服务中自动启动

    1.配置系统参数: JAVA_HOME:C:\Program Files\Java\jdk1.8.0_51   //本机Jdk的安装路径,已配置相关Java应用的无需再配置. CATALINA_HOM ...