FileInputStream是InputStream的直接子类,其特性是专门从文件中创建输入流。
但是,FileInputStream方法底层都调用了native方法,除非去看native方法的源码,不然其源码挺简单的。
package java.io; import java.nio.channels.FileChannel; import sun.nio.ch.FileChannelImpl; /** * FileInputStream 从文件系统中的某个文件中获得输入字节。哪些文件可用取决于主机环境。 * FileInputStream 用于读取诸如图像数据之类的原始字节流。要读取字符流,请考虑使用 FileReader。 */ public class FileInputStream extends InputStream { /* 用于打开文件的文件描述符 */ private final FileDescriptor fd; /** * 文件路径 */ private final String path; private FileChannel channel = null; private final Object closeLock = new Object(); private volatile boolean closed = false; /** * 构造方法1,传入字符串构造File对象,再调用构造方法2 */ public FileInputStream(String name) throws FileNotFoundException { this(name != null ? new File(name) : null); } /** * 构造方法2,传入File对象进行构造。 */ 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); // 调用native方法打开文件 } /** * 构造方法3,通过文件描述符进行构造 */ public FileInputStream(FileDescriptor fdObj) { SecurityManager security = System.getSecurityManager(); if (fdObj == null) { throw new NullPointerException(); } if (security != null) { security.checkRead(fdObj); } fd = fdObj; path = null; fd.attach(this); } /** * native方法打开文件以读取其内容 */ private native void open0(String name) throws FileNotFoundException; /** * 构造方法调用open,open调用open0 */ private void open(String name) throws FileNotFoundException { open0(name); } /** * 从此输入流中读取一个数据字节。如果没有输入可用,则此方法将阻塞。 * 底层还是调用native方法。 */ public int read() throws IOException { return read0(); } private native int read0() throws IOException; // native方法,一次读取一个字节 /** * native方法,用于将数据读入字节数组 */ private native int readBytes(byte b[], int off, int len) throws IOException; /** * 从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。 * 在某些输入可用之前,此方法将阻塞。 * 底层调用native方法 */ public int read(byte b[]) throws IOException { return readBytes(b, 0, b.length); } /** * 从此输入流中将最多 len 个字节的数据读入一个 byte 数组中。 * 如果 len 不为 0,则在输入可用之前,该方法将阻塞;否则,不读取任何字节并返回 0。 * 底层调用native方法 */ public int read(byte b[], int off, int len) throws IOException { return readBytes(b, off, len); } /** * 实现父类的方法,不过是native方法 */ public native long skip(long n) throws IOException; /** * 覆盖父类方法,不过是native方法 */ public native int available() throws IOException; /** * 重写父类方法,底层调用native方法 */ 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(); } }); } /** * 返回表示到文件系统中实际文件的连接的 FileDescriptor 对象 */ public final FileDescriptor getFD() throws IOException { if (fd != null) { return fd; } throw new IOException(); } /** * 返回与此文件输入流有关的唯一 FileChannel 对象。 */ 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(); // 静态代码块,随类的加载而执行,调用了native方法。 } /** * 确保不再引用文件输入流时调用其 close 方法。 */ protected void finalize() throws IOException { if ((fd != null) && (fd != FileDescriptor.in)) { close(); } } }FilterInputStream 包含其他一些输入流,它将这些流用作其基本数据源,它可以直接传输数据或提供一些额外的功能。
其代码同FilterOutputStream一样,没什么具体功能,只是持有父类InputStream对象,并调用父类的同名方法。
// 部分源码 public class FilterInputStream extends InputStream { /** * 持有父类对象 */ protected volatile InputStream in; /** * 构造方法传入父类型对象,当然可以是InputStream的直接子类对象 */ protected FilterInputStream(InputStream in) { this.in = in; } // 方法均调用父类的同名方法FilterInputStream的子类继承自FilterInputStream,自然也就拿到了父类的in对象,然后在本类的同名方法中,可对in对象的方法进行“装饰”,即功能增强。下面分析BufferedInputStream的源码。
package java.io; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; public class BufferedInputStream extends FilterInputStream { private static int DEFAULT_BUFFER_SIZE = 8192; // 默认buffer大小 /** * 最大容量 */ private static int MAX_BUFFER_SIZE = Integer.MAX_VALUE - 8; /** * buffer缓冲区 */ protected volatile byte buf[]; /** * 缓存数组的原子更新器。 * 该成员变量与buf数组的volatile关键字共同组成了buf数组的原子更新功能实现。 */ private static final AtomicReferenceFieldUpdater<BufferedInputStream, byte[]> bufUpdater = AtomicReferenceFieldUpdater.newUpdater (BufferedInputStream.class, byte[].class, "buf"); /** * buffer中的有效字节数 */ protected int count; /** * buffer中的当前位置 */ protected int pos; /** * mark标记位置 */ protected int markpos = -1; /** * mark最大标记位置 */ protected int marklimit; /** * 检查流是否开启 */ private InputStream getInIfOpen() throws IOException { InputStream input = in; if (input == null) throw new IOException("Stream closed"); return input; } /** * 检查buffer是否为空 */ private byte[] getBufIfOpen() throws IOException { byte[] buffer = buf; if (buffer == null) throw new IOException("Stream closed"); return buffer; } /** * 构造方法1,传入InputStream类型“被装饰者”对象,调用构造方法2 */ public BufferedInputStream(InputStream in) { this(in, DEFAULT_BUFFER_SIZE); } /** * 构造方法2,传入"被装饰者"对象,并构造 */ public BufferedInputStream(InputStream in, int size) { super(in); // 调用父类的构造方法 if (size <= 0) { throw new IllegalArgumentException("Buffer size <= 0"); } buf = new byte[size]; // 初始化buffer } /** * 填充方法,将流中的数据写入到buffer中 */ 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; } /** * read()方法底层仍调用了InputStream类型的read()方法, * 不过对其进行了"装饰",即使用了缓冲区技术,从而提高了效率。 */ public synchronized int read() throws IOException { if (pos >= count) { fill(); if (pos >= count) return -1; } return getBufIfOpen()[pos++] & 0xff; } /** * 读入字节数组的方法,供read(byte b[], int off, int len)方法调用 * 底层仍调用InputStream的read()方法 */ private int read1(byte[] b, int off, int len) throws IOException { int avail = count - pos; if (avail <= 0) { 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; } /** * read缓冲区方法,调用read1,对InputStream的read方法进行了"缓冲区装饰" */ 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; } } /** * 仍然是对原方法的"装饰" */ 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; } /** * 装饰方法 */ 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; } /** * 装饰方法 */ public synchronized void mark(int readlimit) { marklimit = readlimit; markpos = pos; } /** * 装饰方法 */ public synchronized void reset() throws IOException { getBufIfOpen(); // Cause exception if closed if (markpos < 0) throw new IOException("Resetting to invalid mark"); pos = markpos; } /** * 测试是否有mark,reset方法支持 */ public boolean markSupported() { return true; } /** * 仍然是对原close()方法的装饰 */ 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() } } }同样有各自的装饰内容,用来装饰InputStream类型对象的方法。
DataInputStream:数据输入流允许应用程序以与机器无关方式从底层输入流中读取基本 Java 数据类型。PushbackInputStream :为另一个输入流添加性能,即“推回 (push back)”或“取消读取 (unread)”一个字节的能力。….