Java_io体系之BufferedWriter、BufferedReader简介、走进源码及示例――16(一)

2014-11-24 08:05:03 · 作者: · 浏览: 3

Java_io体系之BufferedWriter、BufferedReader简介、走进源码及示例――16


一:BufferedWriter


1、类功能简介:


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中、


2、BufferedWriter API简介:


A:关键字

    private Writer out;		 底层字符输出流

   
    private char cb[];		  缓冲数组
    
    private int nChars, nextChar;		 nChars--cb的size,nextChar--cb中下一个字符的下标

    private static int defaultCharBufferSize = 8192;		 默认cb大小

    private String lineSeparator;		换行符、用于newLine方法。不同平台具有不同的值。

B:构造方法


    BufferedWriter(Writer out)		使用默认cb大小创建BufferedWriter  bw。
    
    BufferedWriter(Writer out, int sz)		使用默认cb大小创建BufferedWriter  bw。

C:一般方法


    void close()		关闭此流、释放与此流有关的资源。
    
    void flushBuffer()		将cb中缓存的字符flush到底层out中、
    
    void flush()	刷新此流、同时刷新底层out流
    
    void newLine()		写入一个换行符。
    
    void write(int c)		将一个单个字符写入到cb中。
    
    void write(char cbuf[], int off, int len)	将一个从下标off开始长度为len个字符写入cb中
    
    void write(String s, int off, int len)		将一个字符串的一部分写入cb中

3、源码分析


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 ne