← 返回文章列表

ARTICLE

Java的BufferedReader类学习笔记

BufferedReader由Reader类扩展而来,提供通用的缓冲方式文本读取,而且提供了很实用的readLine,读取一个文本行,从字符输入流中读取文本,缓冲各个字符,从而提供字符、数组和行的高效读取。

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方面的小小的插曲,但是如果我没有注意到这点,可能以后在写一些生产环境用的的系统时,会出现致命的问题。生活如此艰辛,学习过程还需时刻谨慎小心啊!