转载请注明出处: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 {
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;
}
}
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) {
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;
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的缓冲区大小为1KBBufferedReader相对于Scanner来说要快一点,因为Scanner对输入数据进行正则解析,而BufferedReader只是简单地读取字符序列
转载请注明出处:http://blog.csdn.net/linxdcn/article/details/72886231