本文摘抄至 : skywang12345
摘要 : BufferedWriter、缓存字符输出流、他的功能是为传入的底层字符输出流提供缓存功能、同样当使用底层字符输出流向目的地中写入字符或者字符数组时、每写入一次就要打开一次到目的地的连接、这样频繁的访问不断效率底下、也有可能会对存储介质造成一定的破坏、比如当我们向磁盘中不断的写入字节时、夸张一点、将一个非常大单位是G的字节数据写入到磁盘的指定文件中的、没写入一个字节就要打开一次到这个磁盘的通道、这个结果无疑是恐怖的、而当我们使用BufferedWriter将底层字符输出流、比如FileReader包装一下之后、我们可以在程序中先将要写入到文件中的字符写入到BufferedWriter的内置缓存空间中、然后当达到一定数量时、一次性写入FileReader流中、此时、FileReader就可以打开一次通道、将这个数据块写入到文件中、这样做虽然不可能达到一次访问就将所有数据写入磁盘中的效果、但也大大提高了效率和减少了磁盘的访问量!这就是其意义所在、
他的具体 工作原理在这里简单提一下:当程序中每次将字符或者字符数组写入到BufferedWriter中时、都会检查BufferedWriter中的缓存字符数组buf(buf的大小是默认的或者在创建bw时指定的、一般使用默认的就好)是否存满、如果没有存满则将字符写入到buf中、如果存满、则调用底层的writer(char[] b, int off, int len)将buf中的所有字符一次性写入到底层out中、如果写入的是字符数组、如果buf中已满则同上面满的时候的处理、如果能够存下写入的字符数组、则存入buf中、如果存不下、并且要写入buf的字符个数小于buf的长度、则将buf中所有字符写入到out中、然后将要写入的字符存放到buf中(从下标0开始存放)、如果要写入out中的字符超过buf的长度、则直接写入out中、
BufferedWriter 介绍
BufferedWriter 是缓冲字符输出流。它继承于 Writer。
BufferedWriter 的作用是为其它 输出流添加一些缓冲功能
BufferedWriter 函数列表
// 构造函数
BufferedWriter(Writer out)
BufferedWriter(Writer out, int sz)
void close() // 关闭此流,但要先刷新它。
void flush() // 刷新该流的缓冲。
void newLine() // 写入一个行分隔符。
void write(char[] cbuf, int off, int len) // 写入字符数组的某一部分。
void write(int c) // 写入单个字符。
void write(String s, int off, int len) // 写入字符串的某一部分。
BufferedWriter 源码分析(基于jdk1.7.40)
package java.io;
public class BufferedWriter extends Writer {
//输出流对象
private Writer out;
//保存“缓存输出流”数据的字符数组
private char cb[];
//nChars 是 cb缓冲区中字符的总个数
//nextChar 是下一个要读取的字符在 cb缓冲区的位置
private int nChars, nextChar;
//默认字符缓冲去大小 (8k)
private static int defaultCharBufferSize = 8192;
//行分隔符
private String lineSeparator;
//构造函数,传入“writer对象”,默认是缓冲区大小 8k
public BufferedWriter(Writer out) {
this(out, defaultCharBufferSize);
}
//构造函数,传入“Writer对象”,指定缓冲区大小是 sz
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 = java.security.AccessController.doPrivileged(
new sun.security.action.GetPropertyAction("line.separator"));
}
// 确保“BufferedWriter”是打开状态
private void ensureOpen() throws IOException {
if (out == null)
throw new IOException("Stream closed");
}
// 对缓冲区执行flush()操作,将缓冲区的数据写入到Writer中
void flushBuffer() throws IOException {
synchronized (lock) {
ensureOpen();
if (nextChar == 0)
return;
out.write(cb, 0, nextChar);
nextChar = 0;
}
}
//将 c写入到缓冲区中,先将 c转换为 char,然后将其写入缓冲区
public void write(int c) throws IOException {
synchronized (lock) {
ensureOpen();
//如实缓冲区满, 将缓冲数据写入到输出流中
if (nextChar >= nChars)
flushBuffer();
cb[nextChar++] = (char) c;
}
}
//返回, a,b中的较小数
private int min(int a, int b) {
if (a < b) return a;
return b;
}
//将字符数组 cbuf写入到缓冲中,从 cbuf的off位置开始写入,写入长度为 len
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) {
/* If the request length exceeds the size of the output buffer,
flush the buffer and then write the data directly. In this
way buffered streams will cascade harmlessly. */
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();
}
}
}
//将字符串 a 写入到缓冲中,从 a的off位置开始写入,写入长度为 len。
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);
}
//清空缓存数据
public void flush() throws IOException {
synchronized (lock) {
flushBuffer();
out.flush();
}
}
public void close() throws IOException {
synchronized (lock) {
if (out == null) {
return;
}
try (Writer w = out) {
flushBuffer();
} finally {
out = null;
cb = null;
}
}
}
}
说明:
BufferedWriter通过字符数组来缓冲数据,当缓冲区满或者用户调用flush()函数时,它就会将缓冲区的数据写入到输出流中。
示例代码
关于BufferedWriter中API的详细用法,参考示例代码(BufferedWriterTest.java):
public class BufferedWriterTest {
// 对应英文字母“abcdefghijklmnopqrstuvwxyz”
private static final char[] ArrayLetters = new char[]
{'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
public static void main(String[] args) {
testBufferedWriter() ;
}
private static void testBufferedWriter() {
// 创建“文件输出流”对应的BufferedWriter
try {
File file = new File("bufferwriter.txt") ;
BufferedWriter out = new BufferedWriter(
new FileWriter(file)) ;
// 将ArrayLetters数组的前10个字符写入到输出流中
out.write(ArrayLetters, 0, 10) ;
// 将“换行符\n”写入到输出流中
out.write("\n") ;
out.flush() ;
// readUserInput() ;
out.close() ;
} catch (Exception e) {
e.printStackTrace() ;
}
}
private static void readUserInput() {
System.out.println("please input a text:");
Scanner reader = new Scanner(System.in) ;
// 等待一个输入
String str = reader.next() ;
System.out.printf("the input is : %s\n", str);
}
}
运行结果:
生成文件“bufferwriter.txt”,文件的内容是“abcdefghij”。