java IO BufferedReader

InputStream in = new FileInputStream("hello2.txt");
Reader reader = new InputStreamReader(in);
BufferedReader reader2 = new BufferedReader(reader);

//从上面的代码以及官方文档,在加上百度
//BufferedReader  就是为Reader 提供了一个缓存,先把Reader 读取的数据的一部分存入缓存中,等处理后
//在将下一部分否的数据存入缓存中
public class BufferedReader extends Reader

为什么需要缓冲呢?

原因很简单,效率问题!缓冲中的数据实际上是保存在内存中,而原始数据可能是保存在硬盘或NandFlash中;而我们知道,从内存中读取数据的速度比从硬盘读取数据的速度至少快10倍以上。
那干嘛不干脆一次性将全部数据都读取到缓冲中呢?

第一,读取全部的数据所需要的时间可能会很长。

第二,内存价格很贵,容量不想硬盘那么大。

关于构造函数

//默认缓冲区的大小
private static int defaultCharBufferSize = 8192;
//默认每一行字符的数量
private static int defaultExpectedLineLength = 80;
//缓冲区
private char cb[];

//指定大小,但可以不指定大小, 默认的可以满足大部分的需求了
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);
    }

有一点记录一下:

如果第一行没有数据,第二行有数据的话那么

例如:

第一行:

第二行:sdasdasd

cb[0] = '\r' cb[1] = '\n' cb[3] = 's'

private boolean skipLF = false;


//每一才读取做一个字符
//若有字符则返回0 to 65535之间的数字,若到了流的结尾,则返回-1
public int read() throws IOException {
        synchronized (lock) {
            ensureOpen();
            for (;;) {
                if (nextChar >= nChars) {//第一次读取的时候,将流中的数据刷新至缓冲区
                    fill();
                    if (nextChar >= nChars)//如果没有数据,返回-1
                        return -1;
                }
                if (skipLF) {//跳过换行符 '/r'
                    skipLF = false; 
                    if (cb[nextChar] == '\n') {//跳过回车符 '/n'
                        nextChar++;
                        continue;
                    }
                }
                return cb[nextChar++];
            }
        }
    }

//写了一个小程序测试了一下关于 /r /n
//发现 read 可以读取到 /r 与 /n的
//换句话说,skipLF 一直就是默认的false 不知道这样对不对?

//把字符读进指定的数组cbuf,也就是说,将缓冲区数组中的数据复制到指定数组中
 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;
        }
    }


 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;
    }
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;
        }
    }
//每一次读取缓冲区中一行的数据,返回String。若没有数据,返回NULL 
public String readLine() throws IOException {
        return readLine(false);
    }

 String readLine(boolean ignoreLF) throws IOException {
        StringBuffer s = null;
        int startChar;

        synchronized (lock) {
            ensureOpen();
            boolean omitLF = ignoreLF || skipLF;

        bufferLoop:
            for (;;) {

                if (nextChar >= nChars) //刚开始读的时候,全为0,所以是从流中读取数据到缓冲区,当读到最后一行的时候,两个也是相等的,这时候就是刷新缓冲区。
                    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);
            }
        }
    }
//将字符写入输出流的缓冲区,这样字符,数组,字符串高效写入
//可以指定缓冲区的大小,也可以使用默认的大小
public class BufferedWriter extends Writer

private static int defaultCharBufferSize = 8192;

public BufferedWriter(Writer out) {
        this(out, defaultCharBufferSize);
    }

 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"));
    }
//将一个字符写入缓冲区
public void write(int c) throws IOException {
        synchronized (lock) {
            ensureOpen();
            if (nextChar >= nChars)//流中的字符全部写入了,那么刷新缓冲区。
                flushBuffer();
            cb[nextChar++] = (char) c; //写入缓冲区
        }
    }

//将缓冲区的数据刷新到基础字符流,而并不是冲洗流本身
 void flushBuffer() throws IOException {
        synchronized (lock) {
            ensureOpen();
            if (nextChar == 0)
                return;
            out.write(cb, 0, nextChar); //读取缓冲区的数据到字符流中的缓冲区
            nextChar = 0;
        }
    }
//将cbuf中的字符写入缓冲区 
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();
            }
        }
    }
//将一个字符串写入缓冲区
 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();
            }
        }
    }

//写一个行分隔符,是由lineSeparator定义的,并不一定是'/n'
 public void newLine() throws IOException {
        write(lineSeparator);
    }

//刷新基础流
 public void flush() throws IOException {
        synchronized (lock) {
            flushBuffer();
            out.flush();
        }
    }


 @Test
    public void bufferTest() throws IOException {
    	InputStream in = new FileInputStream("C:\\file\\hello.txt");
    	Reader reader = new InputStreamReader(in);
    	BufferedReader bufferedReader = new BufferedReader(reader);
    	OutputStream out = new FileOutputStream("C:\\file\\hello1.txt");
    	Writer writer = new OutputStreamWriter(out);
    	BufferedWriter bufferedWriter = new BufferedWriter(writer);
    	String str = null;
    	while((str = bufferedReader.readLine())!= null) {
    		bufferedWriter.write(str);//,每一次写入一行字符
    		bufferedWriter.newLine(); //如果没有它的话,是不会换行的
    	}
    	
    	bufferedWriter.flush();
    	out.close();
    	in.close();
    	
    }

猜你喜欢

转载自blog.csdn.net/qq_35815781/article/details/85217319