该类引入了:
import java.nio.channels.FileChannel; import sun.nio.ch.FileChannelImpl;
继承了InputStream。
该类的类头注释如下:
/** * A <code>FileInputStream</code> obtains input bytes * from a file in a file system. What files * are available depends on the host environment. * * <p><code>FileInputStream</code> is meant for reading streams of raw bytes * such as image data. For reading streams of characters, consider using * <code>FileReader</code>. * * @author Arthur van Hoff * @see java.io.File * @see java.io.FileDescriptor * @see java.io.FileOutputStream * @see java.nio.file.Files#newInputStream * @since JDK1.0 */
大意如下:
FileInputStream从文件系统的文件中获取输入byte
文件的有效性取决于主机环境
FileInputStream可以直接从原始byte流读取数据(读取出byte数据),例如图像数据
如果要从流中读取字符,请考虑使用FileReader
该类含有如下的成员变量:
文件描述符:
private final FileDescriptor fd;
输入文件的路径:
private final String path;
文件流频道:
private FileChannel channel = null;
线程关闭锁
private final Object closeLock = new Object();
流关闭标示(每次调用时刷新:
private volatile boolean closed = false;
该类含有如下的成员方法:
构造方法(输入文件的路径构造
public FileInputStream(String name) throws FileNotFoundException { this(name != null ? new File(name) : null);//判定文件路径是否为空 }
构造方法(输入该文件投射出的File对象
public FileInputStream(File file) throws FileNotFoundException { String name = (file != null ? file.getPath() : null);//把File类标示的虚拟路径引入 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);//将fd与该对象绑定 path = name; open(name);//打开该文件 }
构造方法(文件描述符构造流,仅绑定了描述符序号,没有给出路径
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); }
打开并读入输入文件(系统native方法,看不见工作原理
private native void open0(String name) throws FileNotFoundException;
同上,调用上一个方法
private void open(String name) throws FileNotFoundException { open0(name); }
从数据流中读入byte数据,如果没有输入流,该方法无效(调用下一个native方法
public int read() throws IOException { return read0(); }
被上个函数调用的read()方法
private native int read0() throws IOException;
读取传入的byte数组中特定位置特定长度的数值(还是native,可以参考我前面写的BufferInputStream
private native int readBytes(byte b[], int off, int len) throws IOException;
读入传入byte数组的全部数值
public int read(byte b[]) throws IOException { return readBytes(b, 0, b.length); }
相当于上个native函数的public转化
public int read(byte b[], int off, int len) throws IOException { return readBytes(b, off, len); }
跳过后续读入的n个字符(参考我前面写的各种BufferInputStream类
public native long skip(long n) throws IOException;
返回当前文章剩余可读取数据(设计思路很清晰,但内部封装无法看出来具体实现
public native int available() throws IOException;
关闭输入流
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();//注销文件描述符 } }); }
返回该流的文件描述符
public final FileDescriptor getFD() throws IOException { if (fd != null) { return fd; } throw new IOException(); }
返回该流的文件流频道
public FileChannel getChannel() { synchronized (this) { if (channel == null) { channel = FileChannelImpl.open(fd, path, true, false, this);//如果为空就申请一个文件流频道 } return channel; } }
jni注册初始化(猜测
private static native void initIDs();
向jvm注销该对象并释放内存(猜测
private native void close0() throws IOException;
确认在没有更多数据流入该流中时或该类不能再被使用到后(代码块失效)自动关闭流
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(); } }
静态代码块:
static { initIDs(); }
该类使用非常频繁,也非常方便,推荐大家深入了解