Java IO流源码笔记

概览

diagrams
Java中的IO源为4个抽象类,2个字节流相关抽象类InputStream,OutputStream. 2个字符流相关抽象类Reader,Writer.直接联系是都实现了Closeable接口,另外,整个IO的代码基于装饰者模式设计,存在大量的组合 > 聚合 > 关联 > 依赖关系,不了解UML模型图和关系的可以点击这里快速了解。我这里为了UML图的可读性,没有打开dependencies。有兴趣的读者可以自己使用IDEA的diagrams功能查看
除了抽象类Reader下面的FilterReader是抽象类,其他实现全部是非抽象类。包括缓冲Buffered,数据Data,文件File,字节数组ByteArray,Object,String等各种字节/字符流实现类
IO实现类中分为两类,一类是被装饰者类,一类是装饰者。被装饰者类就是能够从数据源获取数据的类,比如网络,文件,标准输入/输出等,另一类型是装饰者类,比如BufferedInputStream/BufferedOutputStream等,装饰者类中依赖一个数据源被装饰者类,来实现特定功能,比如缓冲的流读写等,体现在装饰者类的构造函数中需要传入一个被装饰的数据流
字节流抽象类约定的需实现的抽象方法read()返回的是int,即ASCII,而字符流约定需要实现的抽象方法为abstract public int read(char cbuf[], int off, int len) throws IOException;读取字符数据到字符数组cbuf中,返回读取到的字符数int

InputStream-被装饰者超类

package java.io;

/**
 * 此类只有一个抽象方法 read() 所有继承此类的方法必须实现read()方法 用于从输入流中处理读取数据的过程
 */
public abstract class InputStream implements Closeable {

    //顾名思义 最大可跳过的字节数
    private static final int MAX_SKIP_BUFFER_SIZE = 2048;

    /**
     * Reads the next byte of data from the input stream. The value byte is
     * returned as an int in the range 0 to
     * 255. If no byte is available because the end of the stream
     * has been reached, the value -1 is returned. This method
     * blocks until input data is available, the end of the stream is detected,
     * or an exception is thrown.
     *
     * 

A subclass must provide an implementation of this method. * * @return the next byte of data, or -1 if the end of the * stream is reached. * @exception IOException if an I/O error occurs. * 从输入流读取下一个字节 返回0-255的int值 其实就是ASCII 这个方法的实现在输入数据到达前必须阻塞,检测到输入流结束或者抛出异常则此方法可以结束 */ public abstract int read() throws IOException; //读取一批数据到传入的数组b中 public int read(byte b[]) throws IOException { return read(b, 0, b.length); } /** * 源码这里一大堆注释 但是实现其实很简单 * 传入一个数组b,然后正常读取数据,把读出来的字节从off参数位置开始放,总共读取len个字节 */ public int read(byte b[], int off, int len) throws IOException { if (b == null) { throw new NullPointerException(); } else if (off < 0 || len < 0 || len > b.length - off) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } int c = read(); if (c == -1) { return -1; } b[off] = (byte)c; int i = 1; try { for (; i < len ; i++) { c = read(); if (c == -1) { break; } b[off + i] = (byte)c; } } catch (IOException ee) { } return i; } /** * Skips over and discards n bytes of data from this input * stream. The skip method may, for a variety of reasons, end * up skipping over some smaller number of bytes, possibly 0. * This may result from any of a number of conditions; reaching end of file * before n bytes have been skipped is only one possibility. * The actual number of bytes skipped is returned. If {@code n} is * negative, the {@code skip} method for class {@code InputStream} always * returns 0, and no bytes are skipped. Subclasses may handle the negative * value differently. * *

The skip method of this class creates a * byte array and then repeatedly reads into it until n bytes * have been read or the end of the stream has been reached. Subclasses are * encouraged to provide a more efficient implementation of this method. * For instance, the implementation may depend on the ability to seek. * * @param n the number of bytes to be skipped. * @return the actual number of bytes skipped. * @exception IOException if the stream does not support seek, * or if some other I/O error occurs. * 跳过并丢弃n个字节的数据 如果n是负数 则返回0不跳过 官方鼓励实现类用更高效的方法实现 */ public long skip(long n) throws IOException { long remaining = n; int nr; if (n <= 0) { return 0; } int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining); byte[] skipBuffer = new byte[size]; while (remaining > 0) { //不能超过最大跳过大小 nr = read(skipBuffer, 0, (int)Math.min(size, remaining)); //输入流已结束 if (nr < 0) { break; } remaining -= nr; } return n - remaining; } /** * Returns an estimate of the number of bytes that can be read (or * skipped over) from this input stream without blocking by the next * invocation of a method for this input stream. The next invocation * might be the same thread or another thread. A single read or skip of this * many bytes will not block, but may read or skip fewer bytes. * *

Note that while some implementations of {@code InputStream} will return * the total number of bytes in the stream, many will not. It is * never correct to use the return value of this method to allocate * a buffer intended to hold all data in this stream. * *

A subclass' implementation of this method may choose to throw an * {@link IOException} if this input stream has been closed by * invoking the {@link #close()} method. * *

The {@code available} method for class {@code InputStream} always * returns {@code 0}. * *

This method should be overridden by subclasses. * * @return an estimate of the number of bytes that can be read (or skipped * over) from this input stream without blocking or {@code 0} when * it reaches the end of the input stream. * @exception IOException if an I/O error occurs. */ //返回可读字节数 子类应该实现 public int available() throws IOException { return 0; } /** * Closes this input stream and releases any system resources associated * with the stream. * *

The close method of InputStream does * nothing. * * @exception IOException if an I/O error occurs. */ public void close() throws IOException {} /** * Marks the current position in this input stream. A subsequent call to * the reset method repositions this stream at the last marked * position so that subsequent reads re-read the same bytes. * *

The readlimit arguments tells this input stream to * allow that many bytes to be read before the mark position gets * invalidated. * *

The general contract of mark is that, if the method * markSupported returns true, the stream somehow * remembers all the bytes read after the call to mark and * stands ready to supply those same bytes again if and whenever the method * reset is called. However, the stream is not required to * remember any data at all if more than readlimit bytes are * read from the stream before reset is called. * *

Marking a closed stream should not have any effect on the stream. * *

The mark method of InputStream does * nothing. * * @param readlimit the maximum limit of bytes that can be read before * the mark position becomes invalid. * @see java.io.InputStream#reset() */ //可以标记并用reset方法跳回去的一个预定义方法 public synchronized void mark(int readlimit) {} /** * Repositions this stream to the position at the time the * mark method was last called on this input stream. * *

The general contract of reset is: * *

    *
  • If the method markSupported returns * true, then: * *
    • If the method mark has not been called since * the stream was created, or the number of bytes read from the stream * since mark was last called is larger than the argument * to mark at that last call, then an * IOException might be thrown. * *
    • If such an IOException is not thrown, then the * stream is reset to a state such that all the bytes read since the * most recent call to mark (or since the start of the * file, if mark has not been called) will be resupplied * to subsequent callers of the read method, followed by * any bytes that otherwise would have been the next input data as of * the time of the call to reset.
    * *
  • If the method markSupported returns * false, then: * *
    • The call to reset may throw an * IOException. * *
    • If an IOException is not thrown, then the stream * is reset to a fixed state that depends on the particular type of the * input stream and how it was created. The bytes that will be supplied * to subsequent callers of the read method depend on the * particular type of the input stream.
* *

The method reset for class InputStream * does nothing except throw an IOException. * * @exception IOException if this stream has not been marked or if the * mark has been invalidated. * @see java.io.InputStream#mark(int) * @see java.io.IOException */ public synchronized void reset() throws IOException { throw new IOException("mark/reset not supported"); } /** * Tests if this input stream supports the mark and * reset methods. Whether or not mark and * reset are supported is an invariant property of a * particular input stream instance. The markSupported method * of InputStream returns false. * * @return true if this stream instance supports the mark * and reset methods; false otherwise. * @see java.io.InputStream#mark(int) * @see java.io.InputStream#reset() */ public boolean markSupported() { return false; } }

FilterInputStream-装饰者超类

package java.io;

/**
 * A FilterInputStream contains
 * some other input stream, which it uses as
 * its  basic source of data, possibly transforming
 * the data along the way or providing  additional
 * functionality. The class FilterInputStream
 * itself simply overrides all  methods of
 * InputStream with versions that
 * pass all requests to the contained  input
 * stream. Subclasses of FilterInputStream
 * may further override some of  these methods
 * and may also provide additional methods
 * and fields.
 *
 * @author  Jonathan Payne
 * @since   JDK1.0
 * 此类包含一些其他的被装饰者的InputStream,用被装饰者的输入流数据作为基础数据,此类几乎没有干什么事儿 只是把被装饰者的依赖关系包进来了 掉用的都是传入进来的被装饰者的方法
 */
public
class FilterInputStream extends InputStream {
    /**
     * 被装饰者 需要被过滤的输入流 读取方法调用的是传入的in的读取方法
     */
    protected volatile InputStream in;

    protected FilterInputStream(InputStream in) {
        this.in = in;
    }

    public int read() throws IOException {
        return in.read();
    }

    public int read(byte b[]) throws IOException {
        return read(b, 0, b.length);
    }

    public int read(byte b[], int off, int len) throws IOException {
        return in.read(b, off, len);
    }

    public long skip(long n) throws IOException {
        return in.skip(n);
    }

    public int available() throws IOException {
        return in.available();
    }

    public void close() throws IOException {
        in.close();
    }

    public synchronized void mark(int readlimit) {
        in.mark(readlimit);
    }

    public synchronized void reset() throws IOException {
        in.reset();
    }

    public boolean markSupported() {
        return in.markSupported();
    }
}

ByteArrayInputStream-被装饰者的字节数组输入流实现

package java.io;

/**
 * A ByteArrayInputStream contains
 * an internal buffer that contains bytes that
 * may be read from the stream. An internal
 * counter keeps track of the next byte to
 * be supplied by the read method.
 * 

* Closing a ByteArrayInputStream has no effect. The methods in * this class can be called after the stream has been closed without * generating an IOException. * * @author Arthur van Hoff * @see java.io.StringBufferInputStream * @since JDK1.0 * 此实现包含一个内部的字节数组缓冲,用来读取数据流 */ public class ByteArrayInputStream extends InputStream { /** * An array of bytes that was provided * by the creator of the stream. Elements buf[0] * through buf[count-1] are the * only bytes that can ever be read from the * stream; element buf[pos] is * the next byte to be read. * 用于读取输入流的字节数组 */ protected byte buf[]; /** * The index of the next character to read from the input stream buffer. * This value should always be nonnegative * and not larger than the value of count. * The next byte to be read from the input stream buffer * will be buf[pos]. * 下一个待读数组位置 */ protected int pos; /** * The currently marked position in the stream. * ByteArrayInputStream objects are marked at position zero by * default when constructed. They may be marked at another * position within the buffer by the mark() method. * The current buffer position is set to this point by the * reset() method. *

* If no mark has been set, then the value of mark is the offset * passed to the constructor (or 0 if the offset was not supplied). * * @since JDK1.1 * 标记回朔地址 */ protected int mark = 0; /** * The index one greater than the last valid character in the input * stream buffer. * This value should always be nonnegative * and not larger than the length of buf. * It is one greater than the position of * the last byte within buf that * can ever be read from the input stream buffer. * 比有效字符(可读取字符)大的索引,默认为数组长度 */ protected int count; /** * Creates a ByteArrayInputStream * so that it uses buf as its * buffer array. * The buffer array is not copied. * The initial value of pos * is 0 and the initial value * of count is the length of * buf. * * @param buf the input buffer. */ public ByteArrayInputStream(byte buf[]) { this.buf = buf; this.pos = 0; this.count = buf.length; } /** * Creates ByteArrayInputStream * that uses buf as its * buffer array. The initial value of pos * is offset and the initial value * of count is the minimum of offset+length * and buf.length. * The buffer array is not copied. The buffer's mark is * set to the specified offset. * * @param buf the input buffer. * @param offset the offset in the buffer of the first byte to read. * @param length the maximum number of bytes to read from the buffer. */ public ByteArrayInputStream(byte buf[], int offset, int length) { this.buf = buf; this.pos = offset; this.count = Math.min(offset + length, buf.length); this.mark = offset; } /** * Reads the next byte of data from this input stream. The value * byte is returned as an int in the range * 0 to 255. If no byte is available * because the end of the stream has been reached, the value * -1 is returned. *

* This read method * cannot block. * * @return the next byte of data, or -1 if the end of the * stream has been reached. * 这里主要有个0xFF 不知道为何要如此使用? TODO */ public synchronized int read() { return (pos < count) ? (buf[pos++] & 0xff) : -1; } /** * Reads up to len bytes of data into an array of bytes * from this input stream. * If pos equals count, * then -1 is returned to indicate * end of file. Otherwise, the number k * of bytes read is equal to the smaller of * len and count-pos. * If k is positive, then bytes * buf[pos] through buf[pos+k-1] * are copied into b[off] through * b[off+k-1] in the manner performed * by System.arraycopy. The * value k is added into pos * and k is returned. *

* This read method cannot block. * * @param b the buffer into which the data is read. * @param off the start offset in the destination array b * @param len the maximum number of bytes read. * @return the total number of bytes read into the buffer, or * -1 if there is no more data because the end of * the stream has been reached. * @exception NullPointerException If b is null. * @exception IndexOutOfBoundsException If off is negative, * len is negative, or len is greater than * b.length - off * 按量读取 使用System.arraycopy来进行实现 */ public synchronized int read(byte b[], int off, int len) { if (b == null) { throw new NullPointerException(); } else if (off < 0 || len < 0 || len > b.length - off) { throw new IndexOutOfBoundsException(); } if (pos >= count) { return -1; } int avail = count - pos; if (len > avail) { len = avail; } if (len <= 0) { return 0; } System.arraycopy(buf, pos, b, off, len); pos += len; return len; } /** * Skips n bytes of input from this input stream. Fewer * bytes might be skipped if the end of the input stream is reached. * The actual number k * of bytes to be skipped is equal to the smaller * of n and count-pos. * The value k is added into pos * and k is returned. * * @param n the number of bytes to be skipped. * @return the actual number of bytes skipped. * 跳过的实现 直接移动指针位置pos */ public synchronized long skip(long n) { long k = count - pos; if (n < k) { k = n < 0 ? 0 : n; } pos += k; return k; } /** * Returns the number of remaining bytes that can be read (or skipped over) * from this input stream. *

* The value returned is count - pos, * which is the number of bytes remaining to be read from the input buffer. * * @return the number of remaining bytes that can be read (or skipped * over) from this input stream without blocking. */ public synchronized int available() { return count - pos; } /** * Tests if this InputStream supports mark/reset. The * markSupported method of ByteArrayInputStream * always returns true. * * @since JDK1.1 */ public boolean markSupported() { return true; } /** * Set the current marked position in the stream. * ByteArrayInputStream objects are marked at position zero by * default when constructed. They may be marked at another * position within the buffer by this method. *

* If no mark has been set, then the value of the mark is the * offset passed to the constructor (or 0 if the offset was not * supplied). * *

Note: The readAheadLimit for this class * has no meaning. * * @since JDK1.1 */ public void mark(int readAheadLimit) { mark = pos; } /** * Resets the buffer to the marked position. The marked position * is 0 unless another position was marked or an offset was specified * in the constructor. */ public synchronized void reset() { pos = mark; } /** * Closing a ByteArrayInputStream has no effect. The methods in * this class can be called after the stream has been closed without * generating an IOException. */ public void close() throws IOException { } }

BufferedInputStream-装饰者

package java.io;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

/**
 * A BufferedInputStream adds
 * functionality to another input stream-namely,
 * the ability to buffer the input and to
 * support the mark and reset
 * methods. When  the BufferedInputStream
 * is created, an internal buffer array is
 * created. As bytes  from the stream are read
 * or skipped, the internal buffer is refilled
 * as necessary  from the contained input stream,
 * many bytes at a time. The mark
 * operation  remembers a point in the input
 * stream and the reset operation
 * causes all the  bytes read since the most
 * recent mark operation to be
 * reread before new bytes are  taken from
 * the contained input stream.
 *
 * @author  Arthur van Hoff
 * @since   JDK1.0
 * 装饰类 主要在InputStream的基础上 使用一个byte[]来使用缓冲区进行读取
 * 操作的单位从原始类的字节 可以灵活的操作缓冲区数据
 */
public
class BufferedInputStream extends FilterInputStream {

    //顾名思义 默认缓冲区大小
    private static int DEFAULT_BUFFER_SIZE = 8192;

    /**
     * The maximum size of array to allocate.
     * Some VMs reserve some header words in an array.
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     * 最大缓冲区大小 受限于某些VM的数组内存分配策略
     */
    private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8;

    /**
     * The internal buffer array where the data is stored. When necessary,
     * it may be replaced by another array of
     * a different size.
     * 核心缓冲数组
     */
    protected volatile byte buf[];

    /**
     * Atomic updater to provide compareAndSet for buf. This is
     * necessary because closes can be asynchronous. We use nullness
     * of buf[] as primary indicator that this stream is closed. (The
     * "in" field is also nulled out on close.)
     * 保证buf缓冲区的原子操作性 
     */
    private static final
        AtomicReferenceFieldUpdater bufUpdater =
        AtomicReferenceFieldUpdater.newUpdater
        (BufferedInputStream.class,  byte[].class, "buf");

    /**
     * The index one greater than the index of the last valid byte in
     * the buffer.
     * This value is always
     * in the range 0 through buf.length;
     * elements buf[0]  through buf[count-1]
     * contain buffered input data obtained
     * from the underlying  input stream.
     */
    protected int count;

    /**
     * The current position in the buffer. This is the index of the next
     * character to be read from the buf array.
     * 

* This value is always in the range 0 * through count. If it is less * than count, then buf[pos] * is the next byte to be supplied as input; * if it is equal to count, then * the next read or skip * operation will require more bytes to be * read from the contained input stream. * * @see java.io.BufferedInputStream#buf */ protected int pos; /** * The value of the pos field at the time the last * mark method was called. *

* This value is always * in the range -1 through pos. * If there is no marked position in the input * stream, this field is -1. If * there is a marked position in the input * stream, then buf[markpos] * is the first byte to be supplied as input * after a reset operation. If * markpos is not -1, * then all bytes from positions buf[markpos] * through buf[pos-1] must remain * in the buffer array (though they may be * moved to another place in the buffer array, * with suitable adjustments to the values * of count, pos, * and markpos); they may not * be discarded unless and until the difference * between pos and markpos * exceeds marklimit. * * @see java.io.BufferedInputStream#mark(int) * @see java.io.BufferedInputStream#pos */ protected int markpos = -1; /** * The maximum read ahead allowed after a call to the * mark method before subsequent calls to the * reset method fail. * Whenever the difference between pos * and markpos exceeds marklimit, * then the mark may be dropped by setting * markpos to -1. * * @see java.io.BufferedInputStream#mark(int) * @see java.io.BufferedInputStream#reset() */ protected int marklimit; /** * Check to make sure that underlying input stream has not been * nulled out due to close; if not return it; */ private InputStream getInIfOpen() throws IOException { InputStream input = in; if (input == null) throw new IOException("Stream closed"); return input; } /** * Check to make sure that buffer has not been nulled out due to * close; if not return it; */ private byte[] getBufIfOpen() throws IOException { byte[] buffer = buf; if (buffer == null) throw new IOException("Stream closed"); return buffer; } /** * Creates a BufferedInputStream * and saves its argument, the input stream * in, for later use. An internal * buffer array is created and stored in buf. * * @param in the underlying input stream. */ public BufferedInputStream(InputStream in) { this(in, DEFAULT_BUFFER_SIZE); } /** * Creates a BufferedInputStream * with the specified buffer size, * and saves its argument, the input stream * in, for later use. An internal * buffer array of length size * is created and stored in buf. * * @param in the underlying input stream. * @param size the buffer size. * @exception IllegalArgumentException if {@code size <= 0}. */ public BufferedInputStream(InputStream in, int size) { super(in); if (size <= 0) { throw new IllegalArgumentException("Buffer size <= 0"); } buf = new byte[size]; } /** * Fills the buffer with more data, taking into account * shuffling and other tricks for dealing with marks. * Assumes that it is being called by a synchronized method. * This method also assumes that all data has already been read in, * hence pos > count. * 从原始输入流往缓冲区填充数据 */ private void fill() throws IOException { byte[] buffer = getBufIfOpen(); if (markpos < 0) pos = 0; /* no mark: throw away the buffer */ else if (pos >= buffer.length) /* no room left in buffer */ if (markpos > 0) { /* can throw away early part of the buffer */ int sz = pos - markpos; System.arraycopy(buffer, markpos, buffer, 0, sz); pos = sz; markpos = 0; } else if (buffer.length >= marklimit) { markpos = -1; /* buffer got too big, invalidate mark */ pos = 0; /* drop buffer contents */ } else if (buffer.length >= MAX_BUFFER_SIZE) { throw new OutOfMemoryError("Required array size too large"); } else { /* grow buffer */ int nsz = (pos <= MAX_BUFFER_SIZE - pos) ? pos * 2 : MAX_BUFFER_SIZE; if (nsz > marklimit) nsz = marklimit; byte nbuf[] = new byte[nsz]; System.arraycopy(buffer, 0, nbuf, 0, pos); if (!bufUpdater.compareAndSet(this, buffer, nbuf)) { // Can't replace buf if there was an async close. // Note: This would need to be changed if fill() // is ever made accessible to multiple threads. // But for now, the only way CAS can fail is via close. // assert buf == null; throw new IOException("Stream closed"); } buffer = nbuf; } count = pos; int n = getInIfOpen().read(buffer, pos, buffer.length - pos); if (n > 0) count = n + pos; } /** * See * the general contract of the read * method of InputStream. * * @return the next byte of data, or -1 if the end of the * stream is reached. * @exception IOException if this input stream has been closed by * invoking its {@link #close()} method, * or an I/O error occurs. * @see java.io.FilterInputStream#in */ public synchronized int read() throws IOException { if (pos >= count) { fill(); if (pos >= count) return -1; } return getBufIfOpen()[pos++] & 0xff; } /** * Read characters into a portion of an array, reading from the underlying * stream at most once if necessary. */ private int read1(byte[] b, int off, int len) throws IOException { int avail = count - pos; if (avail <= 0) { /* If the requested length is at least as large as the buffer, and if there is no mark/reset activity, do not bother to copy the bytes into the local buffer. In this way buffered streams will cascade harmlessly. */ if (len >= getBufIfOpen().length && markpos < 0) { return getInIfOpen().read(b, off, len); } fill(); avail = count - pos; if (avail <= 0) return -1; } int cnt = (avail < len) ? avail : len; System.arraycopy(getBufIfOpen(), pos, b, off, cnt); pos += cnt; return cnt; } /** * Reads bytes from this byte-input stream into the specified byte array, * starting at the given offset. * *

This method implements the general contract of the corresponding * {@link InputStream#read(byte[], int, int) read} method of * the {@link InputStream} class. As an additional * convenience, it attempts to read as many bytes as possible by repeatedly * invoking the read method of the underlying stream. This * iterated read continues until one of the following * conditions becomes true:

    * *
  • The specified number of bytes have been read, * *
  • The read method of the underlying stream returns * -1, indicating end-of-file, or * *
  • The available method of the underlying stream * returns zero, indicating that further input requests would block. * *
If the first read on the underlying stream returns * -1 to indicate end-of-file then this method returns * -1. Otherwise this method returns the number of bytes * actually read. * *

Subclasses of this class are encouraged, but not required, to * attempt to read as many bytes as possible in the same fashion. * * @param b destination buffer. * @param off offset at which to start storing bytes. * @param len maximum number of bytes to read. * @return the number of bytes read, or -1 if the end of * the stream has been reached. * @exception IOException if this input stream has been closed by * invoking its {@link #close()} method, * or an I/O error occurs. */ public synchronized int read(byte b[], int off, int len) throws IOException { getBufIfOpen(); // Check for closed stream if ((off | len | (off + len) | (b.length - (off + len))) < 0) { throw new IndexOutOfBoundsException(); } else if (len == 0) { return 0; } int n = 0; for (;;) { int nread = read1(b, off + n, len - n); if (nread <= 0) return (n == 0) ? nread : n; n += nread; if (n >= len) return n; // if not closed but no bytes available, return InputStream input = in; if (input != null && input.available() <= 0) return n; } } /** * See the general contract of the skip * method of InputStream. * * @exception IOException if the stream does not support seek, * or if this input stream has been closed by * invoking its {@link #close()} method, or an * I/O error occurs. */ public synchronized long skip(long n) throws IOException { getBufIfOpen(); // Check for closed stream if (n <= 0) { return 0; } long avail = count - pos; if (avail <= 0) { // If no mark position set then don't keep in buffer if (markpos <0) return getInIfOpen().skip(n); // Fill in buffer to save bytes for reset fill(); avail = count - pos; if (avail <= 0) return 0; } long skipped = (avail < n) ? avail : n; pos += skipped; return skipped; } /** * Returns an estimate of the number of bytes that can be read (or * skipped over) from this input stream without blocking by the next * invocation of a method for this input stream. The next invocation might be * the same thread or another thread. A single read or skip of this * many bytes will not block, but may read or skip fewer bytes. *

* This method returns the sum of the number of bytes remaining to be read in * the buffer (count - pos) and the result of calling the * {@link java.io.FilterInputStream#in in}.available(). * * @return an estimate of the number of bytes that can be read (or skipped * over) from this input stream without blocking. * @exception IOException if this input stream has been closed by * invoking its {@link #close()} method, * or an I/O error occurs. */ public synchronized int available() throws IOException { int n = count - pos; int avail = getInIfOpen().available(); return n > (Integer.MAX_VALUE - avail) ? Integer.MAX_VALUE : n + avail; } /** * See the general contract of the mark * method of InputStream. * * @param readlimit the maximum limit of bytes that can be read before * the mark position becomes invalid. * @see java.io.BufferedInputStream#reset() */ public synchronized void mark(int readlimit) { marklimit = readlimit; markpos = pos; } /** * See the general contract of the reset * method of InputStream. *

* If markpos is -1 * (no mark has been set or the mark has been * invalidated), an IOException * is thrown. Otherwise, pos is * set equal to markpos. * * @exception IOException if this stream has not been marked or, * if the mark has been invalidated, or the stream * has been closed by invoking its {@link #close()} * method, or an I/O error occurs. * @see java.io.BufferedInputStream#mark(int) */ public synchronized void reset() throws IOException { getBufIfOpen(); // Cause exception if closed if (markpos < 0) throw new IOException("Resetting to invalid mark"); pos = markpos; } /** * Tests if this input stream supports the mark * and reset methods. The markSupported * method of BufferedInputStream returns * true. * * @return a boolean indicating if this stream type supports * the mark and reset methods. * @see java.io.InputStream#mark(int) * @see java.io.InputStream#reset() */ public boolean markSupported() { return true; } /** * Closes this input stream and releases any system resources * associated with the stream. * Once the stream has been closed, further read(), available(), reset(), * or skip() invocations will throw an IOException. * Closing a previously closed stream has no effect. * * @exception IOException if an I/O error occurs. */ public void close() throws IOException { byte[] buffer; while ( (buffer = buf) != null) { if (bufUpdater.compareAndSet(this, buffer, null)) { InputStream input = in; in = null; if (input != null) input.close(); return; } // Else retry in case a new buf was CASed in fill() } } }

FileInputStream-从文件读书数据的流

package java.io;
import java.nio.channels.FileChannel;
import sun.nio.ch.FileChannelImpl;
//此类的读取实现和一些其他操作 多依赖于c/c++的native本地方法实现
public
class FileInputStream extends InputStream
{
    /* File Descriptor - handle to the open file */
    //文件描述句柄
    private final FileDescriptor fd;

    /**
     * The path of the referenced file
     * (null if the stream is created with a file descriptor)
     */
    //文件路径
    private final String path;

    private FileChannel channel = null;

    //关闭锁对象
    private final Object closeLock = new Object();
    private volatile boolean closed = false;

    /**
     * Creates a FileInputStream by
     * opening a connection to an actual file,
     * the file named by the path name name
     * in the file system.  A new FileDescriptor
     * object is created to represent this file
     * connection.
     * 

* First, if there is a security * manager, its checkRead method * is called with the name argument * as its argument. *

* If the named file does not exist, is a directory rather than a regular * file, or for some other reason cannot be opened for reading then a * FileNotFoundException is thrown. * * @param name the system-dependent file name. * @exception FileNotFoundException if the file does not exist, * is a directory rather than a regular file, * or for some other reason cannot be opened for * reading. * @exception SecurityException if a security manager exists and its * checkRead method denies read access * to the file. * @see java.lang.SecurityManager#checkRead(java.lang.String) * 打开一个文件连接 */ public FileInputStream(String name) throws FileNotFoundException { this(name != null ? new File(name) : null); } /** * Creates a FileInputStream by * opening a connection to an actual file, * the file named by the File * object file in the file system. * A new FileDescriptor object * is created to represent this file connection. *

* First, if there is a security manager, * its checkRead method is called * with the path represented by the file * argument as its argument. *

* If the named file does not exist, is a directory rather than a regular * file, or for some other reason cannot be opened for reading then a * FileNotFoundException is thrown. * * @param file the file to be opened for reading. * @exception FileNotFoundException if the file does not exist, * is a directory rather than a regular file, * or for some other reason cannot be opened for * reading. * @exception SecurityException if a security manager exists and its * checkRead method denies read access to the file. * @see java.io.File#getPath() * @see java.lang.SecurityManager#checkRead(java.lang.String) */ public FileInputStream(File file) throws FileNotFoundException { String name = (file != null ? file.getPath() : null); SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkRead(name); } if (name == null) { throw new NullPointerException(); } if (file.isInvalid()) { throw new FileNotFoundException("Invalid file path"); } fd = new FileDescriptor(); fd.attach(this); path = name; open(name); } /** * Creates a FileInputStream by using the file descriptor * fdObj, which represents an existing connection to an * actual file in the file system. *

* If there is a security manager, its checkRead method is * called with the file descriptor fdObj as its argument to * see if it's ok to read the file descriptor. If read access is denied * to the file descriptor a SecurityException is thrown. *

* If fdObj is null then a NullPointerException * is thrown. *

* This constructor does not throw an exception if fdObj * is {@link java.io.FileDescriptor#valid() invalid}. * However, if the methods are invoked on the resulting stream to attempt * I/O on the stream, an IOException is thrown. * * @param fdObj the file descriptor to be opened for reading. * @throws SecurityException if a security manager exists and its * checkRead method denies read access to the * file descriptor. * @see SecurityManager#checkRead(java.io.FileDescriptor) */ public FileInputStream(FileDescriptor fdObj) { SecurityManager security = System.getSecurityManager(); if (fdObj == null) { throw new NullPointerException(); } if (security != null) { security.checkRead(fdObj); } fd = fdObj; path = null; /* * FileDescriptor is being shared by streams. * Register this stream with FileDescriptor tracker. */ fd.attach(this); } /** * Opens the specified file for reading. * @param name the name of the file */ private native void open0(String name) throws FileNotFoundException; // wrap native call to allow instrumentation /** * Opens the specified file for reading. * @param name the name of the file */ private void open(String name) throws FileNotFoundException { open0(name); } /** * Reads a byte of data from this input stream. This method blocks * if no input is yet available. * * @return the next byte of data, or -1 if the end of the * file is reached. * @exception IOException if an I/O error occurs. * read调用的read0调用的本地读取方法 */ public int read() throws IOException { return read0(); } private native int read0() throws IOException; /** * Reads a subarray as a sequence of bytes. * @param b the data to be written * @param off the start offset in the data * @param len the number of bytes that are written * @exception IOException If an I/O error has occurred. */ private native int readBytes(byte b[], int off, int len) throws IOException; /** * Reads up to b.length bytes of data from this input * stream into an array of bytes. This method blocks until some input * is available. * * @param b the buffer into which the data is read. * @return the total number of bytes read into the buffer, or * -1 if there is no more data because the end of * the file has been reached. * @exception IOException if an I/O error occurs. */ public int read(byte b[]) throws IOException { return readBytes(b, 0, b.length); } /** * Reads up to len bytes of data from this input stream * into an array of bytes. If len is not zero, the method * blocks until some input is available; otherwise, no * bytes are read and 0 is returned. * * @param b the buffer into which the data is read. * @param off the start offset in the destination array b * @param len the maximum number of bytes read. * @return the total number of bytes read into the buffer, or * -1 if there is no more data because the end of * the file has been reached. * @exception NullPointerException If b is null. * @exception IndexOutOfBoundsException If off is negative, * len is negative, or len is greater than * b.length - off * @exception IOException if an I/O error occurs. */ public int read(byte b[], int off, int len) throws IOException { return readBytes(b, off, len); } /** * Skips over and discards n bytes of data from the * input stream. * *

The skip method may, for a variety of * reasons, end up skipping over some smaller number of bytes, * possibly 0. If n is negative, the method * will try to skip backwards. In case the backing file does not support * backward skip at its current position, an IOException is * thrown. The actual number of bytes skipped is returned. If it skips * forwards, it returns a positive value. If it skips backwards, it * returns a negative value. * *

This method may skip more bytes than what are remaining in the * backing file. This produces no exception and the number of bytes skipped * may include some number of bytes that were beyond the EOF of the * backing file. Attempting to read from the stream after skipping past * the end will result in -1 indicating the end of the file. * * @param n the number of bytes to be skipped. * @return the actual number of bytes skipped. * @exception IOException if n is negative, if the stream does not * support seek, or if an I/O error occurs. */ public native long skip(long n) throws IOException; /** * Returns an estimate of the number of remaining bytes that can be read (or * skipped over) from this input stream without blocking by the next * invocation of a method for this input stream. Returns 0 when the file * position is beyond EOF. The next invocation might be the same thread * or another thread. A single read or skip of this many bytes will not * block, but may read or skip fewer bytes. * *

In some cases, a non-blocking read (or skip) may appear to be * blocked when it is merely slow, for example when reading large * files over slow networks. * * @return an estimate of the number of remaining bytes that can be read * (or skipped over) from this input stream without blocking. * @exception IOException if this file input stream has been closed by calling * {@code close} or an I/O error occurs. */ public native int available() throws IOException; /** * Closes this file input stream and releases any system resources * associated with the stream. * *

If this stream has an associated channel then the channel is closed * as well. * * @exception IOException if an I/O error occurs. * * @revised 1.4 * @spec JSR-51 */ public void close() throws IOException { synchronized (closeLock) { if (closed) { return; } closed = true; } if (channel != null) { channel.close(); } fd.closeAll(new Closeable() { public void close() throws IOException { close0(); } }); } /** * Returns the FileDescriptor * object that represents the connection to * the actual file in the file system being * used by this FileInputStream. * * @return the file descriptor object associated with this stream. * @exception IOException if an I/O error occurs. * @see java.io.FileDescriptor */ public final FileDescriptor getFD() throws IOException { if (fd != null) { return fd; } throw new IOException(); } /** * Returns the unique {@link java.nio.channels.FileChannel FileChannel} * object associated with this file input stream. * *

The initial {@link java.nio.channels.FileChannel#position() * position} of the returned channel will be equal to the * number of bytes read from the file so far. Reading bytes from this * stream will increment the channel's position. Changing the channel's * position, either explicitly or by reading, will change this stream's * file position. * * @return the file channel associated with this file input stream * * @since 1.4 * @spec JSR-51 */ public FileChannel getChannel() { synchronized (this) { if (channel == null) { channel = FileChannelImpl.open(fd, path, true, false, this); } return channel; } } private static native void initIDs(); private native void close0() throws IOException; static { initIDs(); } /** * Ensures that the close method of this file input stream is * called when there are no more references to it. * * @exception IOException if an I/O error occurs. * @see java.io.FileInputStream#close() */ protected void finalize() throws IOException { if ((fd != null) && (fd != FileDescriptor.in)) { /* if fd is shared, the references in FileDescriptor * will ensure that finalizer is only called when * safe to do so. All references using the fd have * become unreachable. We can call close() */ close(); } } }

Ref

  1. https://zhuanlan.zhihu.com/p/27931572

你可能感兴趣的:(java,源码)