1: BufferedWriter
1. Introduction to class functions:
BufferedWriter, cache character output stream, its function is to provide cache function for the incoming underlying character output stream. Similarly, when using the underlying character output stream to write characters or character arrays to the destination, the connection to the destination must be opened every time it is written. Such frequent access is constantly efficient, and it may also cause certain damage to the storage medium. For example, when we constantly write bytes to the disk, it is exaggerated to write a very large unit of G to a specified file on the disk, and if we do not write a byte, the channel to this disk must be opened once. This result is undoubtedly terrifying. , and when we use BufferedWriter to wrap the underlying character output stream, such as FileReader, we can first write the characters to be written into the file in the program to the built-in cache space of the BufferedWriter, and then when a certain amount is reached, it will be written into the FileReader stream at one time. At this time, FileReader can open a channel and write this data block to the file. Although it is impossible to achieve the effect of writing all data to the disk in one access, it also greatly improves efficiency and reduces the number of disk accesses! This is its significance. Its specific working principle is briefly mentioned here: It may be quite confusing here. You can look at the source code in detail. If you don’t understand, then look back here. Whenever you write a character or a character array into a BufferedWriter in the program, you will check whether the cached character array buf (the size of buf is the default or specified when creating a bw, generally the default is used) is full. If it is not full, the characters are written into buf. If it is full, the underlying writer(char[] b, int off, int is called, the underlying writer(char[] b, int off, int len) Write all characters in buf to the underlying out at one time, if the character array is written, if the buf is full, the same as the processing when it is full above, if the written character array can be stored, then store it in buf, if the characters to be stored, and the number of characters to be written to buf is less than the length of buf, then write all characters in buf to be written to out, and then store the characters to be written in buf (storage from subscript 0), if the characters to be written in out exceed the length of buf, then write directly to out,
2. Introduction to BufferedWriter API:
A: Keyword private Writer out; Lower character output stream private char cb[]; Buffer array private int nChars, nextChar; nChars--size of the size of nChars, nextChar--subscript of the next character in cb private static int defaultCharBufferSize = 8192; Default cb size private String lineSeparator; newline character, used for newLine method. Different platforms have different values. B: Construct method BufferedWriter(Writer out) creates BufferedWriter bw using the default cb size. BufferedWriter(Writer out, int sz) creates BufferedWriter bw using the default cb size. C: The general method void close() closes this stream and releases resources related to this stream. void flushBuffer() flush the cached characters in cb into the underlying out, void flush() refreshes this stream, and refreshes the underlying out stream void newLine() writes a newline character. void write(int c) writes a single character into cb. void write(char cbuf[], int off, int len) Write a character length of len from the subscript off to cb void write(String s, int off, int len) Write a part of a string to cb
3. Source code analysis
package com.chy.io.original.code;import java.io.IOException;import java.io.PrintWriter;/** * Provide buffering function for character output streams and improve efficiency. You can use the specified character to buffer the array size or the default character to buffer the array size. */public class BufferedWriter extends Writer {//Base array private Writer out; //Buffer array private char cb[]; //nChars--the total number of characters in cb, nextChar--the subscript of the next character in cb private int nChars, nextChar; //Default cb size 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. * Line newline character, used for newLine method. Different platforms have different values. */ private String lineSeparator; /** * Create BufferedWriter bw with the default cb size. */ public BufferedWriter(Writer out) { this(out, defaultCharBufferSize); } /** * Create br and initialize related fields with the specified cb size */ 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;//Get the representation of newline characters under different platforms. lineSeparator =(String) java.security.AccessController.doPrivileged( new sun.security.action.GetPropertyAction("line.separator")); } /** Detect whether the underlying character output stream is closed*/ private void ensureOpen() throws IOException {if (out == null) throw new IOException("Stream closed"); } /** * Flush the cached characters in cb to the underlying out, but not flush the characters in the underlying out. * And clear cb. */ void flushBuffer() throws IOException {synchronized (lock) { ensureOpen(); if (nextChar == 0) return; out.write(cb, 0, nextChar); nextChar = 0;} } /** * Write a single character to 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; } /** * Write a character length of len from the subscript off to 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) {/* If len is greater than the length of cb, then the existing characters in cb and characters in cbuf are directly written to out, instead of writing to cb, and then writing to 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(); }} } /** * Write part of a string to 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(); }} } /** * Write a newline. */ public void newLine() throws IOException { write(lineSeparator); } /** * Refresh this stream and refresh the underlying out stream at the same time*/ public void flush() throws IOException {synchronized (lock) { flushBuffer(); out.flush();} } /** * Close this stream and release resources related to this stream. */ public void close() throws IOException {synchronized (lock) { if (out == null) {return; } try { flushBuffer(); } finally { out.close(); out = null; cb = null; }} }}4. Example demonstration: Use the following BufferedReader to implement copying of character-type files.
Two: BufferedReader
1. Introduction to class functions:
Buffered character input stream, its function is to provide buffering function for the incoming underlying character input stream. It will read the characters in the underlying character input stream (in) into its own buffer (built-in cached character array), and then the program calls the BufferedReader's read method to read the characters in the buffer into the program. When the characters in the buffer are read, the BufferedReader will read the next data block from in and into the buffer for the program to read until the data in in is read. The benefits of doing this are, first, it improves the reading efficiency, and second, it reduces the number of connections to open the storage medium. For detailed reasons, BufferedWriter mentioned below. There is a key method fill(), which is to fill the data from in and fill the data from the buffer every time the data in the buffer is read ten times faster than the one reads from disk! This is a very terrifying improvement in efficiency. At the same time, we cannot specify the buffer size of the BufferedReader without prohibiting. After all, it takes a long time to read in one-time. Secondly, the memory price is relatively expensive. What we can do is try to find reasonable points in it. Generally, we don’t have to worry about it and use the default size of the buffer when creating a BufferedReader.
2. Introduction to the BufferedReader API:
A: Constructing method BufferedReader(Reader in, int sz) creates a BufferedReader based on the specified size and underlying character input stream. br BufferedReader(Reader in) Use the default size to create the buffered stream of the underlying output stream B: General method void close() close this stream and release all resources related to this stream void mark(int readAheadLimit) mark the position of this stream at this time boolean markSupported() determines whether this stream supports marking void reset() reset in reset in the position of the last mark boolean ready() determines whether this stream can read characters int read() reads a single character and returns in an integer form. If the end of in is read, it returns -1. int read(char[] cbuf, int off, int len) Read len characters in cbuf Starting from subscript off, length len String readLine() Read a line long skip(long n) discard n characters in in cbuf
3. Source code analysis
package com.chy.io.original.code;import java.io.IOException;/** * Add character buffering cb array for the underlying character input stream. Improve efficiency* @version 1.1, 13/11/17 * @authorandyChen */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; /* Valid only when markedChar > 0 */ /** If the next character is a line feed, skip it */ 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; /** * Create a BufferedReader based on the specified size and underlying character input stream. 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; } /** * Use the default size to create a buffered stream of the underlying output stream*/ public BufferedReader(Reader in) { this(in, defaultCharBufferSize); } /** Detect whether the underlying character input stream in is closed*/ private void ensureOpen() throws IOException {if (in == null) throw new IOException("Stream closed"); } /** * Fill in 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;} } /** * Read a single character and return as an integer. If the end of in is read, it returns -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++]; }} } /** * Read len characters in in to cbuf from the length len starting from the subscript off*/ 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 both 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; } /** * Read len characters in in to cbuf to length len from the index off from the subscript off*/ 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;} } /** * Read a line from in and ignore line breaks*/ 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(); elsereturn 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); } } } /** * Read a line from in, */ public String readLine() throws IOException { return readLine(false); } /** * Discard n characters in in*/ 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;} } /** * Determine whether cb is empty or whether there are readable characters in the underlying 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();} } /** * Determine whether this stream supports marks*/ public boolean markSupported() { return true; } /** * Mark the position of this stream at this time, and allow reading up to readAheadLimit characters before the call to reset method fails. */ 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;} } /** * Reset the position where in was last marked. That is, the next character is read from the position that is last marked. */ 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;} } //Close this stream and release all resources related to this stream public void close() throws IOException {synchronized (lock) { if (in == null)return; in.close(); in = null; cb = null;} }}4. Example demonstration:
package com.chy.io.original.test;import java.io.BufferedReader;import java.io.BufferedWriter;import java.io.File;import java.io.FileReader;import java.io.FileWriter;import java.io.FileWriter;import java.io.IOException;public class BufferedWriterAndBufferedReaderTest {/** * The test of these two classes here is relatively simple, which is to wrap the file character stream and implement file copying* If you are interested, you can test the efficiency, be lazy, and ignore it*/public static void main(String[] args) throws IOException{File resouceFile = new File("D://test.txt");File targetFile = new File("E://copyOftest.txt");BufferedReader br = new BufferedReader(new FileReader(resouceFile));BufferedWriter bw = new BufferedWriter(new FileWriter(targetFile));char[] cbuf = new char[1024];int n = 0;while((n = br.read(cbuf)) != -1){bw.write(cbuf, 0, n);}//Don't forget to refresh and close the flow, otherwise the resources will not be released in time on the one hand, and on the other hand, it may cause data loss if br.close();bw.flush();bw.close();}}Summarize:
For BufferedReader and BufferedWriter, the essence is to add buffering function to the underlying character input and output stream, first read or write data in the underlying stream in the form of a group of reads at a time, and then operate on the buffer. This not only efficiency, but also saves resources. Finally, in the program, for efficiency reasons, these two classes should be used for low-level streams to decorate them, instead of just holding the stream and directly uploading them, thinking that they can be realized.