Reader
Reader是实现了Readbale与Closeable接口。子类必须实现的方法有两个,read 与 close 方法。
/** * Abstract class for reading character streams. The only methods that a * subclass must implement are read(char[], int, int) and close(). Most * subclasses, however, will override some of the methods defined here in order * to provide higher efficiency, additional functionality, or both. * * * @see BufferedReader * @see LineNumberReader * @see CharArrayReader * @see InputStreamReader * @see FileReader * @see FilterReader * @see PushbackReader * @see PipedReader * @see StringReader * @see Writer * * @author Mark Reinhold * @since JDK1.1 */ public abstract class Reader implements Readable, Closeable { ..... }
lock
lock 用于同步读入流的操作方法,子类应该使用这个对象进行同步,不应该使用 this 或者是在方法上加同步。
/** * 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; }
传入 lock 对象的构造函数
/** * 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; }
read
重载了多个 read 方法,其中的最基本的实现是由子类去实现的。在这个方法的实现中是会对
lock
加synchronized
关键字,也就是直到读完所需的数据前,其他读操作是不可以进行的。直到读取完成、IO错误或者读到了文件尾部才会停止阻塞。
/** * Reads characters into a portion of an array. This method will block * until some input is available, an I/O error occurs, or the end of the * stream is reached. * * @param cbuf Destination buffer * @param off Offset at which to start storing characters * @param len Maximum number of characters to read * * @return The number of characters read, or -1 if the end of the * stream has been reached * * @exception IOException If an I/O error occurs */ abstract public int read(char cbuf[], int off, int len) throws IOException;
首先获取
target
中中剩余可以操作的元素的个数,即limit-position
,然后从当前流中读入len
个字符,最后将这些字符写入到target
中,这个方法的本意是读取一些字符到CharBuffer
中
/** * Attempts to read characters into the specified character buffer. * The buffer is used as a repository of characters as-is: the only * changes made are the results of a put operation. No flipping or * rewinding of the buffer is performed. * * @param target the buffer to read characters into * @return The number of characters added to the buffer, or * -1 if this source of characters is at its end * @throws IOException if an I/O error occurs * @throws NullPointerException if target is null * @throws java.nio.ReadOnlyBufferException if target is a read only buffer * @since 1.5 */ 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; }
读取一个字符
/** * Reads a single character. This method will block until a character is * available, an I/O error occurs, or the end of the stream is reached. * * <p> Subclasses that intend to support efficient single-character input * should override this method. * * @return The character read, as an integer in the range 0 to 65535 * (<tt>0x00-0xffff</tt>), or -1 if the end of the stream has * been reached * * @exception IOException If an I/O error occurs */ public int read() throws IOException { char cb[] = new char[1]; if (read(cb, 0, 1) == -1) return -1; else return cb[0]; }
读取固定长度的字符到数组中
/** * Reads characters into an array. This method will block until some input * is available, an I/O error occurs, or the end of the stream is reached. * * @param cbuf Destination buffer * * @return The number of characters read, or -1 * if the end of the stream * has been reached * * @exception IOException If an I/O error occurs */ public int read(char cbuf[]) throws IOException { return read(cbuf, 0, cbuf.length); }
skip/mark/reset/markSupport
最大可跳过字符数,以及跳过数组定义。使用
skip
方法将跳过的字符放置在数组中。以及markSupport
、mark
、reset
方法与InputStream
中定义的差不多。
/** 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 supports the mark() operation. The default * implementation always returns false. Subclasses should override this * method. * * @return true if and only if this stream supports the mark operation. */ public boolean markSupported() { return false; } /** * Marks the present position in the stream. Subsequent calls to reset() * will attempt to reposition the stream to this point. Not all * character-input streams support the mark() operation. * * @param readAheadLimit Limit on the number of characters that may be * read while still preserving the mark. After * reading this many characters, attempting to * reset the stream may fail. * * @exception IOException If the stream does not support mark(), * or if some other I/O error occurs */ public void mark(int readAheadLimit) throws IOException { throw new IOException("mark() not supported"); } /** * Resets the stream. If the stream has been marked, then attempt to * reposition it at the mark. If the stream has not been marked, then * attempt to reset it in some way appropriate to the particular stream, * for example by repositioning it to its starting point. Not all * character-input streams support the reset() operation, and some support * reset() without supporting mark(). * * @exception IOException If the stream has not been marked, * or if the mark has been invalidated, * or if the stream does not support reset(), * or if some other I/O error occurs */ public void reset() throws IOException { throw new IOException("reset() not supported"); }
ready
ready()函数,在子类的实现中可能会使用
synchronized (lock)
,并在方法内判断是否可读。
/** * Tells whether this stream is ready to be read. * * @return True if the next read() is guaranteed not to block for input, * false otherwise. Note that returning false does not guarantee that the * next read will block. * * @exception IOException If an I/O error occurs */ public boolean ready() throws IOException { return false; }
close
close()函数,关闭流,有的方法实现中会加上
synchronized (lock)
,然后再去关闭(比如数组为将数组设置为null),但是有的不会而是直接关闭,所以可能会到导致其他方法的操作出现IOException
/** * Closes the stream and releases any system resources associated with * it. Once the stream has been closed, further read(), ready(), * mark(), reset(), or skip() invocations will throw an IOException. * Closing a previously closed stream has no effect. * * @exception IOException If an I/O error occurs */ abstract public void close() throws IOException;
Writer
是抽象类,子类需要必须实现的方法有三个,write(char[], int, int),flush(),close()
/** * Abstract class for writing to character streams. The only methods that a * subclass must implement are write(char[], int, int), flush(), and close(). * Most subclasses, however, will override some of the methods defined here in * order to provide higher efficiency, additional functionality, or both. * * @see Writer * @see BufferedWriter * @see CharArrayWriter * @see FilterWriter * @see OutputStreamWriter * @see FileWriter * @see PipedWriter * @see PrintWriter * @see StringWriter * @see Reader * * @author Mark Reinhold * @since JDK1.1 */ public abstract class Writer implements Appendable, Closeable, Flushable { ....... }
writeBuffer
用于暂存字符串或者单个字符的。由于所有的写都是使用
write(char[], int, int)
这种方式写入的,所以需要将写入的字符或字符串先保存在数组中,然后进行写入。由于读出首先需要的就是存放容器,所以Reader
不需要专门的暂存容器。
/** * Temporary buffer used to hold writes of strings and single characters */ private char[] writeBuffer; /** * Size of writeBuffer, must be >= 1 */ private static final int WRITE_BUFFER_SIZE = 1024;
lock
锁定义与构造函数定义
/** * 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; }
write/fluse/close 抽象方法
子类必须实现的写入方法。
flush
函数,如果是数组流,则直接将流写入,如果是文件流这种,只是调用操作系统的写入,但是有没有写入是由操作系统决定的。调用close
首先会调用flush
方法。
/** * Writes a portion of an array of characters. * * @param cbuf * Array of characters * * @param off * Offset from which to start writing characters * * @param len * Number of characters to write * * @throws IOException * If an I/O error occurs */ abstract public void write(char cbuf[], int off, int len) throws IOException; /** * 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;
write重载函数
写入单个字符,单个字符使用
int
类型传入,但是int
是4字节,而char
是两字节,所以只取int
的低16位
/** * 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); }
写入字符串,首先将判断字符串长度,若长度大于
WRITE_BUFFER_SIZE
,则新建一个字符串长度的数组,否则使用WRITE_BUFFER_SIZE
长度的数组。然后将string
中的字符赋值给char
数组,最后写入流中
/** * Writes a string. * * @param str * String to be written * * @throws IOException * If an I/O error occurs */ public void write(String str) throws IOException { write(str, 0, str.length()); } /** * Writes a portion of a string. * * @param str * A String * * @param off * Offset from which to start writing characters * * @param len * Number of characters to write * * @throws IndexOutOfBoundsException * If <tt>off</tt> is negative, or <tt>len</tt> is negative, * or <tt>off+len</tt> is negative or greater than the length * of the given string * * @throws IOException * If an I/O error occurs */ 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); } }
append
append方法,也是将字符写入流中。有的传入
CharSequence
,append
函数最后返回当前写入流,这是我感觉出来的唯一方便使用的地方。图片来自 https://www.cnblogs.com/skywang12345/p/string01.html
/** * Appends the specified character sequence to this writer. * * <p> An invocation of this method of the form <tt>out.append(csq)</tt> * behaves in exactly the same way as the invocation * * <pre> * out.write(csq.toString()) </pre> * * <p> Depending on the specification of <tt>toString</tt> for the * character sequence <tt>csq</tt>, the entire sequence may not be * appended. For instance, invoking the <tt>toString</tt> method of a * character buffer will return a subsequence whose content depends upon * the buffer's position and limit. * * @param csq * The character sequence to append. If <tt>csq</tt> is * <tt>null</tt>, then the four characters <tt>"null"</tt> are * appended to this writer. * * @return This writer * * @throws IOException * If an I/O error occurs * * @since 1.5 */ 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; }