2.1 高效流BufferedReader和BufferedWriter的优势
提高效率:为了提高字符流读写的效率,引入了缓冲机制,进行字符批量的读写,提高了单个字符读写的效率。BufferedReader用于加快读取字符的速度,BufferedWriter用于加快写入的速度。
简化了操作。
2.2 BufferedReader 缓冲区大小
BufferedReader和BufferedWriter类各拥有8192个字符的缓冲区。当BufferedReader在读取文本文件时,会先尽量从文件中读入字符数据并放满缓冲区,而之后若使用read()方法,会先从缓冲区中进行读取。如果缓冲区数据不足,才会再从文件中读取,使用BufferedWriter时,写入的数据并不会先输出到目的地,而是先存储至缓冲区中。如果缓冲区中的数据满了,才会一次对目的地进行写出。
2.3 ReusableBufferedReader:可重用的 BufferedReader
标准 Java 的弱点之一BufferedReader是它只能使用一次。一旦你关闭它,它就不再可用。如果需要读取大量文件或网络流,则必须为要读取的每个文件或网络流创建一个新的 BufferedReader。这意味着您正在创建一个新对象,更重要的是,创建一个新的 char 数组,该数组用作 BufferedReader 内的缓冲区。如果读取的文件或流的数量很高,并且它们被快速读取,这会给 Java 垃圾收集器带来压力。
另一种方法是创建一个可重用的 BufferedReader ,您可以在其中替换基础 source Reader,因此可以重用 BufferedReader 及其内部字节数组缓冲区。为了省去您的麻烦,我创建了这样一个ReusableBufferedReader,并在本教程的后面包含了它的代码。首先,我想向您展示如何使用它ReusableBufferedReader。
//构造一个ReusableBufferedReader(2M的内存缓存区)
ReusableBufferedReader reusableBufferedReader = new ReusableBufferedReader(new char[1024 * 1024]);
//创建来源
FileReader reader = new FileReader("/mydata/somefile.txt");
reusableBufferedReader.setSource(reader);
使用完后,ReusableBufferedReader您需要关闭它。
关闭它只会关闭底层源Reader。关闭 a 后,ReusableBufferedReader 您可以再次使用它,只需Reader在其上设置新源即可。
这是重用 a 的样子ReusableBufferedReader:
reusableBufferedReader.setSource(new FileReader("/mydata/file-1.txt"));
//从 ReusableBufferedReader 读取数据
reusableBufferedReader.close();
reusableBufferedReader.setSource(new FileReader("/mydata/file-1.txt"));
//从 ReusableBufferedReader 读取数据
reusableBufferedReader.close();
2.4 readLine()方法的原理和newLine()的底层原理
readLine():无论是读一行,获取读取多个字符,其最终都是在硬盘上一个一个的读取。所以最终使用的还是read()方法一次读一个的方法。
newLine():根据系统来决定换行符
注意 不同的操作系统中换行符是不同的
* window:Windows系统里面,每行结尾是 回车 换行(CR LF),即“\r\n”;
* linux:Unix系统里,每行结尾只有 换行CR,即“\n”;
* mac:Mac系统里,每行结尾是 回车CR 即'\r'。
2.5 System.in
从标准输入流System.in中直接读取使用者输入时,使用者每输入一个字符,System.in就读取一个字符。为了能一次读取一行使用者的输入,使用了BufferedReader来对使用者输入的字符进行缓冲。readLine()方法会在读取到使用者的换行字符时,再一次将整行字符串传入。
System.in是一个位流,为了转换为字符流,可使用InputStreamReader为其进行字符转换,然后再使用BufferedReader为其增加缓冲功能。
3 简单用例3.1 进行文件的拷贝
@Test
public void IOTest01() throws Exception{
BufferedReader br = new BufferedReader(new FileReader("D:\\javaio\test01.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\javaio\\test02.txt"));
// char[] cbuf = new char[1024];
// int len;
// while((len=br.read(cbuf)) != -1){
// bw.write(cbuf, 0, len);
// }
//BufferedReader提供了readLine方法,可以不再使用字节读取方式
String readline;
while((readline = br.readLine()) != null){
bw.write(readline);
bw.newLine();
}
bw.close();
br.close();
}
3.2 将文件追加到文件上
@Test
public void IOTest2() throws Exception{
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\test.txt",true));
bw.write("我是测试用例!");
bw.close();
}
3.3 读取文件内容
@Test
public void IOTest3() throws Exception{
BufferedReader br = new BufferedReader(new FileReader("D:\\test.txt"));
String readline;
while((readline = br.readLine()) != null){
System.out.println(readline);
}
br.close();
}
4 源码
4.1 BufferedWriter源码分析
package com.chy.io.original.code;
import java.io.IOException;
import java.io.PrintWriter;
/**
* 为字符输出流提供缓冲功能、提高效率。可以使用指定字符缓冲数组大小也可以使用默认字符缓冲数组大小。
*/
public class BufferedWriter extends Writer {
//底层字符输出流
private Writer out;
//缓冲数组
private char cb[];
//nChars--cb中总的字符数,nextChar--cb中下一个字符的下标
private int nChars, nextChar;
//默认cb大小
private static int defaultCharBufferSize = 8192;
/**
* Line separator string. This is the value of the line.separator
* property at the moment that the stream was created.
* 换行符、用于newLine方法。不同平台具有不同的值。
*/
private String lineSeparator;
/**
* 使用默认cb大小创建BufferedWriter bw。
*/
public BufferedWriter(Writer out) {
this(out, defaultCharBufferSize);
}
/**
* 使用指定cb大小创建br、初始化相关字段
*/
public BufferedWriter(Writer out, int sz) {
super(out);
if (sz <= 0)
throw new IllegalArgumentException("Buffer size <= 0");
this.out = out;
cb = new char[sz];
nChars = sz;
nextChar = 0;
//获取不同平台下的换行符表示方式。
lineSeparator = (String) java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("line.separator"));
}
/** 检测底层字符输出流是否关闭*/
private void ensureOpen() throws IOException {
if (out == null)
throw new IOException("Stream closed");
}
/**
* 将cb中缓存的字符flush到底层out中、但是不flush底层out中的字符。
* 并且将cb清空。
*/
void flushBuffer() throws IOException {
synchronized (lock) {
ensureOpen();
if (nextChar == 0)
return;
out.write(cb, 0, nextChar);
nextChar = 0;
}
}
/**
* 将一个单个字符写入到cb中。
*/
public void write(int c) throws IOException {
synchronized (lock) {
ensureOpen();
if (nextChar >= nChars)
flushBuffer();
cb[nextChar ] = (char) c;
}
}
/**
* Our own little min method, to avoid loading java.lang.Math if we've run
* out of file descriptors and we're trying to print a stack trace.
*/
private int min(int a, int b) {
if (a < b) return a;
return b;
}
/**
* 将一个从下标off开始长度为len个字符写入cb中
*/
public void write(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;
}
if (len >= nChars) {
/* 如果len大于cb的长度、那么就直接将cb中现有的字符和cbuf中的字符写入out中、
* 而不是写入cb、再写入out中 。
*/
flushBuffer();
out.write(cbuf, off, len);
return;
}
int b = off, t = off len;
while (b < t) {
int d = min(nChars - nextChar, t - b);
System.arraycopy(cbuf, b, cb, nextChar, d);
b = d;
nextChar = d;
if (nextChar >= nChars)
flushBuffer();
}
}
}
/**
* 将一个字符串的一部分写入cb中
*/
public void write(String s, int off, int len) throws IOException {
synchronized (lock) {
ensureOpen();
int b = off, t = off len;
while (b < t) {
int d = min(nChars - nextChar, t - b);
s.getChars(b, b d, cb, nextChar);
b = d;
nextChar = d;
if (nextChar >= nChars)
flushBuffer();
}
}
}
/**
* 写入一个换行符。
*/
public void newLine() throws IOException {
write(lineSeparator);
}
/**
* 刷新此流、同时刷新底层out流
*/
public void flush() throws IOException {
synchronized (lock) {
flushBuffer();
out.flush();
}
}
/**
* 关闭此流、释放与此流有关的资源。
*/
public void close() throws IOException {
synchronized (lock) {
if (out == null) {
return;
}
try {
flushBuffer();
} finally {
out.close();
out = null;
cb = null;
}
}
}
}
4.2 BufferedReader 源码分析
package com.chy.io.original.code;
import java.io.IOException;
/**
* 为底层字符输入流添加字符缓冲cb数组。提高效率
*/
public class BufferedReader extends Reader {
private Reader in;
private char cb[];
private int nChars, nextChar;
private static final int INVALIDATED = -2;
private static final int UNMARKED = -1;
private int markedChar = UNMARKED;
private int readAheadLimit = 0;
private boolean skipLF = false;
/** The skipLF flag when the mark was set */
private boolean markedSkipLF = false;
private static int defaultCharBufferSize = 8192;
private static int defaultExpectedLineLength = 80;
/**
* 根据指定大小和底层字符输入流创建BufferedReader。br
*/
public BufferedReader(Reader in, int sz) {
super(in);
if (sz <= 0)
throw new IllegalArgumentException("Buffer size <= 0");
this.in = in;
cb = new char[sz];
nextChar = nChars = 0;
}
/**
* 使用默认大小创建底层输出流的缓冲流
*/
public BufferedReader(Reader in) {
this(in, defaultCharBufferSize);
}
/** 检测底层字符输入流in是否关闭 */
private void ensureOpen() throws IOException {
if (in == null)
throw new IOException("Stream closed");
}
/**
* 填充cb。
*/
private void fill() throws IOException {
int dst;
if (markedChar <= UNMARKED) {
/* No mark */
dst = 0;
} else {
/* Marked */
int delta = nextChar - markedChar;
if (delta >= readAheadLimit) {
/* Gone past read-ahead limit: Invalidate mark */
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 {
/* Reallocate buffer to accommodate read-ahead limit */
char ncb[] = new char[readAheadLimit];
System.arraycopy(cb, markedChar, ncb, 0, delta);
cb = ncb;
markedChar = 0;
dst = delta;
}
nextChar = nChars = delta;
}
}
int n;
do {
n = in.read(cb, dst, cb.length - dst);
} while (n == 0);
if (n > 0) {
nChars = dst n;
nextChar = dst;
}
}
/**
* 读取单个字符、以整数形式返回。如果读到in的结尾则返回-1。
*/
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 ];
}
}
}
/**
* 将in中len个字符读取到cbuf从下标off开始长度len中
*/
private int read1(char[] cbuf, int off, int len) throws IOException {
if (nextChar >= nChars) {
/* If the requested length is at least as large as the buffer, and
if there is no mark/reset activity, and if line feeds are not
being skipped, do not bother to copy the characters into the
local buffer. In this way buffered streams will cascade
harmlessly. */
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;
}
/**
* 将in中len个字符读取到cbuf从下标off开始长度len中
*/
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;
}
}
/**
* 从in中读取一行、是否忽略换行符
*/
String readLine(boolean ignoreLF) throws IOException {
StringBuffer s = null;
int startChar;
synchronized (lock) {
ensureOpen();
boolean omitLF = ignoreLF || skipLF;
bufferLoop:
for (;;) {
if (nextChar >= nChars)
fill();
if (nextChar >= nChars) { /* EOF */
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:
for (i = nextChar; i < nChars; i ) {
c = cb[i];
if ((c == '\n') || (c == '\r')) {
eol = true;
break charLoop;
}
}
startChar = nextChar;
nextChar = i;
if (eol) {
String str;
if (s == null) {
str = new String(cb, startChar, i - startChar);
} else {
s.append(cb, startChar, i - startChar);
str = s.toString();
}
nextChar ;
if (c == '\r') {
skipLF = true;
}
return str;
}
if (s == null)
s = new StringBuffer(defaultExpectedLineLength);
s.append(cb, startChar, i - startChar);
}
}
}
/**
* 从in中读取一行、
*/
public String readLine() throws IOException {
return readLine(false);
}
/**
* 丢弃in中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;
}
}
/**
* 判断cb中是否为空、或者底层in中是否有可读字符。
*/
public boolean ready() throws IOException {
synchronized (lock) {
ensureOpen();
/*
* If newline needs to be skipped and the next char to be read
* is a newline character, then just skip it right away.
*/
if (skipLF) {
/* Note that in.ready() will return true if and only if the next
* read on the stream will not block.
*/
if (nextChar >= nChars && in.ready()) {
fill();
}
if (nextChar < nChars) {
if (cb[nextChar] == '\n')
nextChar ;
skipLF = false;
}
}
return (nextChar < nChars) || in.ready();
}
}
/**
* 判断此流是否支持标记
*/
public boolean markSupported() {
return true;
}
/**
* 标记此流此时的位置、当调用reset方法失效前最多允许读取readAheadLimit个字符。
*/
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;
}
}
/**
* 重置in被最后一次mark的位置。即下一个字符从被最后一次mark的位置开始读取。
*/
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;
in.close();
in = null;
cb = null;
}
}
}
Copyright © 2024 妖气游戏网 www.17u1u.com All Rights Reserved