【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
Reader是所有xxxReader类的父类,子类需要重写
BufferedReader的
读取到指定长度的字符
输入流返回-1表示结束
输入流的ready函数返回false,说明请求新的字符将会被阻塞,直接返回
BufferedReader的构造函数需要传入一个Reader,对于InputStream或者File,可以通过InputStreamReader和FileReader进行包装后传入,代码如下:
(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
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)BufferedReaderBufferedReader的构造函数需要传入一个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
相关文章推荐
- Java BufferedWriter BufferedReader 源码分析
- 【Java部分源码分析之io篇】6.InputStreamReader
- Java_io体系之BufferedWriter、BufferedReader简介、走进源码及示例——16
- Java IO学习笔记(九):BufferedReader和Scanner
- java.io.BufferedInputStream 源码分析
- java IO(二):内存操作流、管道流、打印流、System对IO的支持、BufferedReader、Scanner
- Java IO:PipedReader和PipedWriter使用详解及源码分析
- 【Java部分源码分析之io篇】7.FileReader
- Java IO完全总结(转载) --- 重点在源码分析
- Java_io体系之BufferedWriter、BufferedReader简介、源码示例
- Java IO学习笔记(九):BufferedReader和Scanner
- Java IO学习9:BufferedReader和Scanner
- Java IO:BufferedInputStream使用详解及源码分析
- Java_io体系之BufferedWriter、BufferedReader简介、走进源码及示例——16
- Java IO:CharArrayReader使用及源码分析
- Java_io体系之CharArrayReader、CharArrayWriter简介、走进源码及示例——13
- java io系列02之 ByteArrayInputStream的简介,源码分析和示例(包括InputStream)
- Java -- 键盘输入 Scanner, BufferedReader。 系统相关System,Runtime。随机数 Randrom。日期操作Calendar
- java io系列04之 管道(PipedOutputStream和PipedInputStream)的简介,源码分析和示例
- Java IO--BufferedReader