JDK源码:BufferedReader
Posted jdkSpring
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDK源码:BufferedReader相关的知识,希望对你有一定的参考价值。
BufferedReader是为了提供读的效率而设计的一个包装类,它可以包装字符流。可以从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取.
BufferReader的作用是为其它Reader提供缓冲功能。创建BufferReader时,我们会通过它的构造函数指定某个Reader为参数。BufferReader会将该Reader中的数据分批读取,每次读取一部分到缓冲中;操作完缓冲中的这部分数据之后,再从Reader中读取下一部分的数据。
类名
public class BufferedReader extends Reader
Reader是一个抽象类,它是以字符为单位的输入流的公共父类。
成员变量
private Reader in;//字符输入流
private char cb[];//字符缓冲区
// nChars 是cb缓冲区中字符的总的个数
// nextChar 是下一个要读取的字符在cb缓冲区中的位置
private int nChars, nextChar;
// 表示“标记无效”。它与UNMARKED的区别是:
// (01) UNMARKED 是压根就没有设置过标记。
// (02) 而INVALIDATED是设置了标记,但是被标记位置太长,导致标记无效!
private static final int INVALIDATED = -2;
private static final int UNMARKED = -1;
// “标记”
private int markedChar = UNMARKED;
// “标记”能标记位置的最大长度
private int readAheadLimit = 0; /* Valid only when markedChar > 0 */
// 如果下个字符是换行符,则跳过--专用于readLine()方法里面控制
private boolean skipLF = false;
// 设置“标记”时,保存的skipLF的值--用于mark()方法的变量
private boolean markedSkipLF = false;
//默认的缓冲区大小
private static int defaultCharBufferSize = 8192;
//用于readLine()方法时初始化StringBuffer的初始容量
private static int defaultExpectedLineLength = 80;
方法
// 创建“Reader”对应的BufferedReader对象,
// sz是BufferedReader的缓冲区大小
public BufferedReader(Reader in, int sz)
// 创建“Reader”对应的BufferedReader对象,
// 默认的BufferedReader缓冲区大小是8k
public BufferedReader(Reader in)
// 确保“BufferedReader”是打开状态
private void ensureOpen() throws IOException
// 填充缓冲区函数。有以下两种情况被调用:
// (01) 缓冲区没有数据时,通过fill()可以向缓冲区填充数据。
// (02) 缓冲区数据被读完,需更新时,通过fill()可以更新缓冲区的数据。
private void fill() throws IOException
// 从BufferedReader中读取一个字符,该字符以int的方式返回
public int read() throws IOException
// 将缓冲区中的数据写入到数组cbuf中。
// off是数组cbuf中的写入起始位置,len是写入长度
private int read1(char[] cbuf, int off, int len) throws IOException
// 对read1()的封装,添加了“同步处理”和“阻塞式读取”等功能
public int read(char cbuf[], int off, int len) throws IOException
// 读取一行数据。ignoreLF是“是否忽略换行符”
String readLine(boolean ignoreLF) throws IOException
// 读取一行数据。不忽略换行符
public String readLine() throws IOException
// 跳过n个字符
public long skip(long n) throws IOException
// “下一个字符”是否可读
public boolean ready() throws IOException
// 始终返回true。因为BufferedReader支持mark(), reset()
public boolean markSupported()
// 标记当前BufferedReader的下一个要读取位置。
public void mark(int readAheadLimit) throws IOException
// 重置BufferedReader的下一个要读取位置,
// 将其还原到mark()中所保存的位置。
public void reset() throws IOException
// 关闭reader
public void close() throws IOException
fill()
private void fill() throws IOException {
// dst表示“cb中填充数据的起始位置”。
int dst;
if (markedChar <= UNMARKED) {
// 没有标记的情况,则设dst=0。
dst = 0;
} else {
// delta表示“当前标记的长度”,
// 它等于“下一个被读取字符的位置”减去“标记的位置”的差值;
int delta = nextChar - markedChar;
if (delta >= readAheadLimit) {
// 若“当前标记的长度”超过了“标记上限(readAheadLimit)”,
// 则丢弃标记!
markedChar = INVALIDATED;
readAheadLimit = 0;
dst = 0;
} else {
if (readAheadLimit <= cb.length) {
/** 若“当前标记的长度”没有超过了“标记上限(readAheadLimit)”,
* 并且“标记上限(readAheadLimit)”小于/等于“缓冲的长度”;
* 则先将“下一个要被读取的位置,距离我们标记的字符的距离”间的
* 字符保存到cb中。
*/
System.arraycopy(cb, markedChar, cb, 0, delta);
markedChar = 0;
dst = delta;
} else {
/** 若“当前标记的长度”没有超过了“标记上限(readAheadLimit)”,
* 并且“标记上限(readAheadLimit)”大于“缓冲的长度”;
* 则重新设置缓冲区大小,
* 并将“下一个要被读取的位置,距离我们标记的字符的距离”间的字符
* 保存到cb中。
*/
char ncb[] = new char[readAheadLimit];
System.arraycopy(cb, markedChar, ncb, 0, delta);
cb = ncb;
markedChar = 0;
dst = delta;
}
// 更新nextChar和nChars
nextChar = nChars = delta;
}
}
int n;
do {
// 从“in”中读取数据,并存储到字符数组cb中;
// 从cb的dst位置开始存储,读取的字符个数是cb.length - dst
// n是实际读取的字符个数;若n==0(即一个也没读到),则继续读取!
n = in.read(cb, dst, cb.length - dst);
} while (n == 0);
// 如果从“in”中读到了数据,则设置nChars(cb中字符的数目)=dst+n,
// 并且nextChar(下一个被读取的字符的位置)=dst。
if (n > 0) {
nChars = dst + n;
nextChar = dst;
}
}
read()
// 从BufferedReader中读取一个字符,该字符以int的方式返回
public int read() throws IOException {
synchronized (lock) {
ensureOpen();
for (;;) {
// 若“缓冲区的数据已经被读完”,
// 则先通过fill()更新缓冲区数据
if (nextChar >= nChars) {
fill();
if (nextChar >= nChars)
return -1;
}
// 若要“忽略换行符”,
// 则对下一个字符是否是换行符进行处理。
if (skipLF) {
skipLF = false;
if (cb[nextChar] == '\n') {
nextChar++;
continue;
}
}
// 返回下一个字符
return cb[nextChar++];
}
}
}
readLine(boolean ignoreLF)
/**
* 阅读一行文字。换行符('\n')、回车符('\r')或紧跟换行符的回车符.
*/
String readLine(boolean ignoreLF) throws IOException {
StringBuffer s = null;
int startChar;
synchronized (lock) {
ensureOpen();
boolean omitLF = ignoreLF || skipLF;
//外循环bufferLoop
bufferLoop:
for (;;) {
if (nextChar >= nChars)// 第一次读入缓冲区
fill();
if (nextChar >= nChars) { /* EOF */
//输入流in对象没有可读字符了
if (s != null && s.length() > 0)
return s.toString();
else
return null;
}
boolean eol = false;
char c = 0;
int i;
/* Skip a leftover '\n', if necessary */
//跳过换行符
if (omitLF && (cb[nextChar] == '\n'))
nextChar++;
skipLF = false;
omitLF = false;
//内循环charLoop【识别cb[]内部是否有换行符】
charLoop:
for (i = nextChar; i < nChars; i++) {
c = cb[i];
if ((c == '\n') || (c == '\r')) {
eol = true;
//跳出内循环,执行内循环下面的代码
break charLoop;
}
}
startChar = nextChar;
// nextChar此时指向\n或\r或缓冲区末尾
nextChar = i;
if (eol) {
String str;
if (s == null) {
//范围为上一个nextChar的位置到\n或\r或缓冲区末尾的位置
str = new String(cb, startChar, i - startChar);
} else {
s.append(cb, startChar, i - startChar);
str = s.toString();
}
//跳过\n
nextChar++;
//跳过换行
if (c == '\r') {
skipLF = true;
}
return str;
}
if (s == null)
s = new StringBuffer(defaultExpectedLineLength);
s.append(cb, startChar, i - startChar);
}
}
}
使用readLine()一定要注意:
1.读入的数据要注意有/r或/n或/r/n
2.没有数据时会阻塞,在文件读取结束和数据流异常或断开时才会返回null
3.使用socket之类的数据流时,要谨慎使用readLine(),以免为了等待一个换行/回车符而一直阻塞
代码注释
public class BufferedReader extends Reader {
private Reader in;//字符输入流
private char cb[];//字符缓冲区
//nChars:读取字符存储的结束下标,nextChar:读取字符存储的开始下标
private int nChars, nextChar;
private static final int INVALIDATED = -2;
private static final int UNMARKED = -1;
private int markedChar = UNMARKED;
private int readAheadLimit = 0; /* Valid only when markedChar > 0 */
// 如果下个字符是换行符,则跳过--专用于readLine()方法里面控制
private boolean skipLF = false;
// 设置标志时的markedSkipLF--用于mark()方法的变量
private boolean markedSkipLF = false;
//默认的缓冲区大小
private static int defaultCharBufferSize = 8192;
//用于readLine()方法时初始化StringBuffer的初始容量
private static int defaultExpectedLineLength = 80;
/**
* 创建一个指定缓冲区大小的缓冲字符输入流
*
* @param in A Reader
* @param sz Input-buffer size
*
* @exception IllegalArgumentException If {@code sz <= 0}
*/
public BufferedReader(Reader in, int sz) {
super(in);
if (sz <= 0)
throw new IllegalArgumentException("Buffer size <= 0");
this.in = in;
cb = new char[sz];
//初始从0开始读
nextChar = nChars = 0;
}
/**
* 创建一个默认缓冲区大小的缓冲字符输入流
*
* @param in A Reader
*/
public BufferedReader(Reader in) {
this(in, defaultCharBufferSize);
}
/** 检查输入流是否关闭 */
private void ensureOpen() throws IOException {
if (in == null)
throw new IOException("Stream closed");
}
/**
* 填充输入缓冲区,并考虑标记是否有效.
*/
private void fill() throws IOException {
int dst;
if (markedChar <= UNMARKED) {//没有标记
dst = 0;
} else {
/* Marked */
int delta = nextChar - markedChar;
if (delta >= readAheadLimit) {
/* 超过预读限制:无效标记 */
markedChar = INVALIDATED;
readAheadLimit = 0;
dst = 0;
} else {
if (readAheadLimit <= cb.length) {
/* Shuffle in the current buffer */
System.arraycopy(cb, markedChar, cb, 0, delta);
markedChar = 0;
dst = delta;
} else {
/* 将内部缓冲字符数组cb[]扩容至readAheadLimit大小*/
char ncb[] = new char[readAheadLimit];
System.arraycopy(cb, markedChar, ncb, 0, delta);
cb = ncb;
markedChar = 0;
dst = delta;
}
nextChar = nChars = delta;
}
}
int n;
do {
//从输入源对象in读取cb剩余空闲个数的字符,从dst索引处开始写入
n = in.read(cb, dst, cb.length - dst);
} while (n == 0);
if (n > 0) {
//读满cb[]
nChars = dst + n;
nextChar = dst;
}
}
/**
* Reads a single character.
*
* @return The character read, as an integer in the range
* 0 to 65535 (<tt>0x00-0xffff</tt>), or -1 if the
* end of the stream has been reached
* @exception IOException If an I/O error occurs
*/
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++];
}
}
}
/**
* 将字符读入数组的一部分,必要时从底层流读取
*/
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读取的是cb.length+1,则返回-1
if (nextChar >= nChars) return -1;
if (skipLF) {
skipLF = false;
//如果是换行,nextChar+1
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;
}
/**
* Reads characters into a portion of an array.
*/
public int read(char cbuf[], int off, int len) throws IOException {
synchronized (lock) {
ensureOpen();
if ((off < 0) || (off > cbuf.length) || (len < 0) ||
((off + len) > cbuf.length) || ((off + len) < 0)) {
throw new IndexOutOfBoundsException();
} else if (len == 0) {
return 0;
}
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;
}
}
/**
* 阅读一行文字。换行符('\n')、回车符('\r')或紧跟换行符的回车符.
*/
String readLine(boolean ignoreLF) throws IOException {
StringBuffer s = null;
int startChar;
synchronized (lock) {
ensureOpen();
boolean omitLF = ignoreLF || skipLF;
//外循环bufferLoop
bufferLoop:
for (;;) {
if (nextChar >= nChars)//第一次读入内容
fill();
if (nextChar >= nChars) { /* EOF */
//输入流in对象没有可读字符了
if (s != null && s.length() > 0)
return s.toString();
else
return null;
}
boolean eol = false;
char c = 0;
int i;
/* Skip a leftover '\n', if necessary */
//跳过换行符
if (omitLF && (cb[nextChar] == '\n'))
nextChar++;
skipLF = false;
omitLF = false;
//内循环charLoop【识别cb[]内部是否有换行符】
charLoop:
for (i = nextChar; i < nChars; i++) {
c = cb[i];
if ((c == '\n') || (c == '\r')) {
eol = true;
//跳出内循环,执行内循环下面的代码
break charLoop;
}
}
startChar = nextChar;
// nextChar此时指向\n或\r或缓冲区末尾
nextChar = i;
if (eol) {
String str;
if (s == null) {
//范围为上一个nextChar的位置到\n或\r或缓冲区末尾的位置
str = new String(cb, startChar, i - startChar);
} else {
s.append(cb, startChar, i - startChar);
str = s.toString();
}
//跳过\n
nextChar++;
//跳过换行
if (c == '\r') {
skipLF = true;
}
return str;
}
if (s == null)
s = new StringBuffer(defaultExpectedLineLength);
s.append(cb, startChar, i - startChar);
}
}
}
public String readLine() throws IOException {
return readLine(false);
}
/**
* 跳过n个字符
*/
public long skip(long n) throws IOException {
if (n < 0L) {
throw new IllegalArgumentException("skip value is negative");
}
synchronized (lock) {
ensureOpen();
long r = n;
while (r > 0) {
if (nextChar >= nChars)
fill();
if (nextChar >= nChars) /* EOF */
break;
if (skipLF) {
skipLF = false;
if (cb[nextChar] == '\n') {
nextChar++;
}
}
long d = nChars - nextChar;
if (r <= d) {
nextChar += r;
r = 0;
break;
}
else {
r -= d;
nextChar = nChars;
}
}
return n - r;
}
}
/**
* 此流是否准备好读取。如果缓冲区不是空的,
* 或者如果基础字符流已准备就绪,则缓冲字符流已准备就绪
*
*/
public boolean ready() throws IOException {
synchronized (lock) {
ensureOpen();
/*
* 如果需要跳过换行符,
* 而下一个要读取的字符是换行符,那么就直接跳过它
*/
if (skipLF) {
/* 注意,in.ready()将返回true,
* 前提是且仅当流上的下一次读取不会阻塞
*/
if (nextChar >= nChars && in.ready()) {
fill();
}
if (nextChar < nChars) {
if (cb[nextChar] == '\n')
nextChar++;
skipLF = false;
}
}
return (nextChar < nChars) || in.ready();
}
}
/**
* Tells whether this stream supports the mark() operation, which it does.
*/
public boolean markSupported() {
return true;
}
/**
* 标记流中的当前位置。对reset()的后续调用将尝试将流重新定位到此点。
*/
public void mark(int readAheadLimit) throws IOException {
if (readAheadLimit < 0) {
throw new IllegalArgumentException("Read-ahead limit < 0");
}
synchronized (lock) {
ensureOpen();
this.readAheadLimit = readAheadLimit;
markedChar = nextChar;
markedSkipLF = skipLF;
}
}
/**
* 将流重置为最新标记
*/
public void reset() throws IOException {
synchronized (lock) {
ensureOpen();
if (markedChar < 0)
throw new IOException((markedChar == INVALIDATED)
? "Mark invalid"
: "Stream not marked");
nextChar = markedChar;
skipLF = markedSkipLF;
}
}
public void close() throws IOException {
synchronized (lock) {
if (in == null)
return;
try {
in.close();
} finally {
in = null;
cb = null;
}
}
}
/**
* 返回一个Stream 里面的元素为读到的所有行内容
*/
public Stream<String> lines() {
Iterator<String> iter = new Iterator<String>() {
String nextLine = null;
public boolean hasNext() {
if (nextLine != null) {
return true;
} else {
try {
nextLine = readLine();
return (nextLine != null);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}
}
public String next() {
if (nextLine != null || hasNext()) {
String line = nextLine;
nextLine = null;
return line;
} else {
throw new NoSuchElementException();
}
}
};
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(
iter, Spliterator.ORDERED | Spliterator.NONNULL), false);
}
}
以上是关于JDK源码:BufferedReader的主要内容,如果未能解决你的问题,请参考以下文章
java缓冲字符字节输入输出流:java.io.BufferedReaderjava.io.BufferedWriterjava.io.BufferedInputStreamjava.io.(代码片段
Android 逆向类加载器 ClassLoader ( 类加载器源码简介 | BaseDexClassLoader | DexClassLoader | PathClassLoader )(代码片段
初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段