以字符为单位的输入流的公共父类是Reader:
以字符为单位的输出流的超类是Writer:
基于JDK8的Reader的源码:
public abstract class Reader implements Readable, Closeable { /** * The object used to synchronize operations on this stream. For * efficiency, a character-stream object may use an object other than * itself to protect critical sections. A subclass should therefore use * the object in this field rather than <tt>this</tt> or a synchronized * method. */ protected Object lock; /** * Creates a new character-stream reader whose critical sections will * synchronize on the reader itself. */ protected Reader() { this.lock = this; } /** * Creates a new character-stream reader whose critical sections will * synchronize on the given object. * * @param lock The Object to synchronize on. */ protected Reader(Object lock) { if (lock == null) { throw new NullPointerException(); } this.lock = lock; } //尝试读字符进字符缓冲 public int read(java.nio.CharBuffer target) throws IOException { int len = target.remaining(); char[] cbuf = new char[len]; int n = read(cbuf, 0, len); if (n > 0) target.put(cbuf, 0, n); return n; } //读单个字符,方法会阻塞直到字符是有效,出现IO错误,或者流完毕 public int read() throws IOException { char cb[] = new char[1]; if (read(cb, 0, 1) == -1) return -1; else return cb[0]; } //读字符数组 public int read(char cbuf[]) throws IOException { return read(cbuf, 0, cbuf.length); } abstract public int read(char cbuf[], int off, int len) throws IOException; /** Maximum skip-buffer size */ private static final int maxSkipBufferSize = 8192; /** Skip buffer, null until allocated */ private char skipBuffer[] = null; /** * Skips characters. This method will block until some characters are * available, an I/O error occurs, or the end of the stream is reached. * * @param n The number of characters to skip * * @return The number of characters actually skipped * * @exception IllegalArgumentException If <code>n</code> is negative. * @exception IOException If an I/O error occurs */ public long skip(long n) throws IOException { if (n < 0L) throw new IllegalArgumentException("skip value is negative"); int nn = (int) Math.min(n, maxSkipBufferSize); synchronized (lock) { if ((skipBuffer == null) || (skipBuffer.length < nn)) skipBuffer = new char[nn]; long r = n; while (r > 0) { int nc = read(skipBuffer, 0, (int)Math.min(r, nn)); if (nc == -1) break; r -= nc; } return n - r; } } /** * Tells whether this stream is ready to be read. * */ //是否准备好去读 public boolean ready() throws IOException { return false; } //不支持标记 public boolean markSupported() { return false; } //会抛出错误 public void mark(int readAheadLimit) throws IOException { throw new IOException("mark() not supported"); } //不支持reset,会抛出错误 public void reset() throws IOException { throw new IOException("reset() not supported"); } //关闭资源 abstract public void close() throws IOException; }
基于JDK8的Writer源码:
public abstract class Writer implements Appendable, Closeable, Flushable { /** * Temporary buffer used to hold writes of strings and single characters */ //写缓冲数组 private char[] writeBuffer; /** * Size of writeBuffer, must be >= 1 */ //写缓冲数组默认大小是1024 private static final int WRITE_BUFFER_SIZE = 1024; /** * The object used to synchronize operations on this stream. For * efficiency, a character-stream object may use an object other than * itself to protect critical sections. A subclass should therefore use * the object in this field rather than <tt>this</tt> or a synchronized * method. */ //对象 protected Object lock; /** * Creates a new character-stream writer whose critical sections will * synchronize on the writer itself. */ // protected Writer() { this.lock = this; } /** * Creates a new character-stream writer whose critical sections will * synchronize on the given object. * * @param lock * Object to synchronize on */ protected Writer(Object lock) { if (lock == null) { throw new NullPointerException(); } this.lock = lock; } /** * Writes a single character. The character to be written is contained in * the 16 low-order bits of the given integer value; the 16 high-order bits * are ignored. * * <p> Subclasses that intend to support efficient single-character output * should override this method. * * @param c * int specifying a character to be written * * @throws IOException * If an I/O error occurs */ //写一个字符 public void write(int c) throws IOException { synchronized (lock) { if (writeBuffer == null){ writeBuffer = new char[WRITE_BUFFER_SIZE]; } writeBuffer[0] = (char) c; write(writeBuffer, 0, 1); } } /** * Writes an array of characters. * * @param cbuf * Array of characters to be written * * @throws IOException * If an I/O error occurs */ //写一个字符数组 public void write(char cbuf[]) throws IOException { write(cbuf, 0, cbuf.length); } abstract public void write(char cbuf[], int off, int len) throws IOException; //写一个String public void write(String str) throws IOException { write(str, 0, str.length()); } //写一个字符串的一部分 public void write(String str, int off, int len) throws IOException { synchronized (lock) { char cbuf[]; if (len <= WRITE_BUFFER_SIZE) { if (writeBuffer == null) { writeBuffer = new char[WRITE_BUFFER_SIZE]; } cbuf = writeBuffer; } else { // Don't permanently allocate very large buffers. cbuf = new char[len]; } str.getChars(off, (off + len), cbuf, 0); write(cbuf, 0, len); } } //追加 public Writer append(CharSequence csq) throws IOException { if (csq == null) write("null"); else write(csq.toString()); return this; } /** * Appends a subsequence of the specified character sequence to this writer. * <tt>Appendable</tt>. * * <p> An invocation of this method of the form <tt>out.append(csq, start, * end)</tt> when <tt>csq</tt> is not <tt>null</tt> behaves in exactly the * same way as the invocation * * <pre> * out.write(csq.subSequence(start, end).toString()) </pre> * * @param csq * The character sequence from which a subsequence will be * appended. If <tt>csq</tt> is <tt>null</tt>, then characters * will be appended as if <tt>csq</tt> contained the four * characters <tt>"null"</tt>. * * @param start * The index of the first character in the subsequence * * @param end * The index of the character following the last character in the * subsequence * * @return This writer * * @throws IndexOutOfBoundsException * If <tt>start</tt> or <tt>end</tt> are negative, <tt>start</tt> * is greater than <tt>end</tt>, or <tt>end</tt> is greater than * <tt>csq.length()</tt> * * @throws IOException * If an I/O error occurs * * @since 1.5 */ public Writer append(CharSequence csq, int start, int end) throws IOException { CharSequence cs = (csq == null ? "null" : csq); write(cs.subSequence(start, end).toString()); return this; } /** * Appends the specified character to this writer. * * <p> An invocation of this method of the form <tt>out.append(c)</tt> * behaves in exactly the same way as the invocation * * <pre> * out.write(c) </pre> * * @param c * The 16-bit character to append * * @return This writer * * @throws IOException * If an I/O error occurs * * @since 1.5 */ public Writer append(char c) throws IOException { write(c); return this; } /** * Flushes the stream. If the stream has saved any characters from the * various write() methods in a buffer, write them immediately to their * intended destination. Then, if that destination is another character or * byte stream, flush it. Thus one flush() invocation will flush all the * buffers in a chain of Writers and OutputStreams. * * <p> If the intended destination of this stream is an abstraction provided * by the underlying operating system, for example a file, then flushing the * stream guarantees only that bytes previously written to the stream are * passed to the operating system for writing; it does not guarantee that * they are actually written to a physical device such as a disk drive. * * @throws IOException * If an I/O error occurs */ abstract public void flush() throws IOException; /** * Closes the stream, flushing it first. Once the stream has been closed, * further write() or flush() invocations will cause an IOException to be * thrown. Closing a previously closed stream has no effect. * * @throws IOException * If an I/O error occurs */ abstract public void close() throws IOException; }