BufferedReader由Reader类扩展而来,提供通用的缓冲方式文本读取,而且提供了很实用的readLine,读取一个文本行,从字符输入流中读取文本,缓冲各个字符,从而提供字符、数组和行的高效读取。
BufferedReader的主要方法
构造方法:
BufferedReader br = new BufferReader(Reader in);
主要方法:
int read();//读取单个字符。
//将字符读入到数组的某一部分。返回读取的字符数。达到尾部 ,返回-1。
int read(char[] cbuf,int off,int len);
String readLine();//读取一个文本行。
void close(); //关闭该流。并释放与该流相关的所有资源。
今天在学习Java的BIO(blocking IO)的时候,在读取socket的输入流数据时,采用了BufferdReader的readLine方法,发现一直阻塞。后来才发现使用readLine方法读取一行必须要有“\r\n“,否则会一直阻塞到Socket超时或者IO异常。下面是我测试时的代码:
未正常处理的代码
BIOClient:
package me.huding.study.distributed;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
public class BIOClient {
public static void main(String[] args) throws UnknownHostException, IOException {
Socket socket = new Socket(“localhost”, 7878);
socket.setSoTimeout(30000);
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
PrintWriter writer = new PrintWriter(socket.getOutputStream(),true);
writer.write(“hello server”);
writer.flush();
String string = reader.readLine();
System.out.println(string);
socket.close();
}
}
BIOServer:
package me.huding.study.distributed;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;
public class BIOServer {
public static void main(String[] args) throws UnknownHostException, IOException {
ServerSocket serverSocket = new ServerSocket(7878);
Socket socket = serverSocket.accept();
BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String string = reader.readLine();
System.out.println(string);
PrintWriter writer = new PrintWriter(socket.getOutputStream(), true);
writer.write("hello client");
writer.flush();
socket.close();
}
}
先运行BIOServer,在运行BIOClient,会发现控制台没有输出预期的结果,即BIOServer输出“hello Server”,BIOClient输出“hello client”,而是输出这样的结果:
BIOServer的结果:
hello server
BIOClient的结果:
Exception in thread "main" java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:170)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:284)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:326)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:178)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:161)
at java.io.BufferedReader.readLine(BufferedReader.java:324)
at java.io.BufferedReader.readLine(BufferedReader.java:389)
at me.huding.study.distributed.BIOClient.main(BIOClient.java:18)
其中BIOClient的结果是因为Socket读取超时出现的。经过简单思考,只要分别将BIOClient的第16行的代码换成:writer.write(“hello server\r\n”);或者writer.println(“hello server”);,将BIOServer的第20行代码替换成:writer.write(“hello client\r\n”);或者writer.println(“hello client”);然后分别运行BIOServer和BIOClient的代码,就可以出线理想的结果:
BIOClient的结果:
hello client
BIOServer的结果:
hello server
总结
虽然我在学习Java的IO方面的小小的插曲,但是如果我没有注意到这点,可能以后在写一些生产环境用的的系统时,会出现致命的问题。生活如此艰辛,学习过程还需时刻谨慎小心啊!