您的位置:首页 > Web前端

【Java8源码分析】IO包-Reader、BufferedReader和Scanner总结

2017-06-06 22:11 417 查看
转载请注明出处:http://blog.csdn.net/linxdcn/article/details/72886231

Java的IO类型可分为两大类:

面向字符流:Reader & Writer

面向字节流:InputStream & OutputStream

本文主要从源码方面分析一下常用的面向字符流的Reader。

Reader:所有字符流的抽象父类,定义了常用输入函数

BufferedReader:带有缓冲区的高效输入流

本文还会介绍一个常用的类:Scanner

1 Reader源码解析

public abstract class Reader implements Readable, Closeable {

// 读一个字符
public int read() throws IOException {
char cb[] = new char[1];
if (read(cb, 0, 1) == -1)
return -1;
else
return cb[0];
}

public int read(char cbuf[]) throws IOException {
return read(cbuf, 0, cbuf.length);
}

// 最主要的函数,子类需重写,读取一定长度的字符串
abstract public int read(char cbuf[], int off, int len) throws IOException;
}


Reader是所有xxxReader类的父类,子类需要重写
read(char[], int, int)
方法,大部分子类也会重写部分方法以提高效率。

2 BufferedReader源码解析

2.1 read()函数

public class BufferedReader extends Reader {

// 内部保存的Reader变量
private Reader in;

// 缓冲区
private char cb[];

// 默认缓冲区大小
private static int defaultCharBufferSize = 8192;

// 填充缓冲区的函数
private void fill() throws IOException {
int dst;

// 省略了部分定位的代码

int n;
do {
// 一次性读满缓冲区
n = in.read(cb, dst, cb.length - dst);
} while (n == 0);
if (n > 0) {
nChars = dst + n;
nextChar = dst;
}
}

cf4d
// 读取一个字符
public int read() throws IOException {
synchronized (lock) {
ensureOpen();
for (;;) {
if (nextChar >= nChars) {
// 如果缓冲区读完了,填充
fill();
if (nextChar >= nChars)
return -1;
}
if (skipLF) {
skipLF = false;
// 跳过换行符
if (cb[nextChar] == '\n') {
nextChar++;
continue;
}
}
return cb[nextChar++];
}
}
}
}


BufferedReader的
read()
函数会读取一个字符,并且会跳过换行符。

read()
都是从缓冲区中获取字符,缓冲区的默认大小为8KB,如果缓冲区读完了,则会调用
fill()
函数对缓冲区进行填充,然后再继续读。
fill()
则调用了
read(char[], int, int)
对缓冲区进行一次性填充。

2.2 read(char[], int, int)函数

public int read(char cbuf[], int off, int len) throws IOException {
synchronized (lock) {

int n = read1(cbuf, off, len);
// 无更多的字符
if (n <= 0) return n;
// 未读满,且输入流已经就绪
while ((n < len) && in.ready()) {
int n1 = read1(cbuf, off + n, len - n);
if (n1 <= 0) break;
n += n1;
}
return n;
}
}

private int read1(char[] cbuf, int off, int len) throws IOException {
if (nextChar >= nChars) {
if (len >= cb.length && markedChar <= UNMARKED && !skipLF) {
// 调用输入流的read填充缓冲区
return in.read(cbuf, off, len);
}
// 缓冲区字符不足,则填充
fill();
}
if (nextChar >= nChars) return -1;
if (skipLF) {
skipLF = false;
if (cb[nextChar] == '\n') {
nextChar++;
if (nextChar >= nChars)
fill();
if (nextChar >= nChars)
return -1;
}
}
int n = Math.min(len, nChars - nextChar);
System.arraycopy(cb, nextChar, cbuf, off, n);
nextChar += n;
return n;
}


read(char[], int, int)
函数会尝试读取尽可能多的字符到数组中,直到满足以下条件之一停止:

读取到指定长度的字符

输入流返回-1表示结束

输入流的ready函数返回false,说明请求新的字符将会被阻塞,直接返回

2.3 readLine函数

readLine()
函数是返回从当前的缓冲位置,到换行符之间的字符串,即从缓冲区当前位置开始的一行。

3 Scanner源码解析

public final class Scanner implements Iterator<String>, Closeable {

// 缓冲区
private CharBuffer buf;

// 缓冲区大小1KB
private static final int BUFFER_SIZE = 1024;

public String nextLine() {
// 如果缓冲中的下一次匹配是行匹配,则直接返回
if (hasNextPattern == linePattern())
return getCachedResult();
clearCaches();

// 否则通过正则表达式匹配返回一行字符串
String result = findWithinHorizon(linePattern, 0);
if (result == null)
throw new NoSuchElementException("No line found");
MatchResult mr = this.match();
String lineSep = mr.group(1);
if (lineSep != null)
result = result.substring(0, result.length() - lineSep.length());
if (result == null)
throw new NoSuchElementException();
else
return result;
}
}


Sanner
中的读取函数,不管是
nextInt()
,还是
nextLine()
都是采用正则匹配的方式读取的。

nextLine()
函数是返回从当前的缓冲位置,到换行符之间的字符串,即从缓冲区当前位置开始的一行。

4 总结

(1)BufferedReader

BufferedReader的构造函数需要传入一个Reader,对于InputStream或者File,可以通过InputStreamReader和FileReader进行包装后传入,代码如下:

BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

BufferedReader br = new BufferedReader(new FileReader("foo.in"));


(2)Reader和Scanner总结

Java.util.Scanner类是一个简单的文本扫描类,它可以解析基本数据类型和字符串。它本质上是使用正则表达式去读取不同的数据类型

Java.io.BufferedReader类为了能够高效的读取字符序列,从字符输入流和字符缓冲区读取文本

(3)readLine和nextLine函数

不管是Reader还是Scanner,如果之前调用read()或者nextXxx()读取过字符,再调用readLine()或者nextLine(0函数,都是读取本行剩余部分。

(4)Reader和Scanner比较

BufferedReader是支持同步的,而Scanner不支持。BufferedReader的read函数都加了synchronized关键字

BufferedReader的缓冲区大小为8KB,Scanner的缓冲区大小为1KB

BufferedReader相对于Scanner来说要快一点,因为Scanner对输入数据进行正则解析,而BufferedReader只是简单地读取字符序列

转载请注明出处:http://blog.csdn.net/linxdcn/article/details/72886231
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: