`

FileInputStream 源码分析

阅读更多
java.io.FileInputStream是从文件系统中获取一个文件的原始字节。如果要读取字符流,可以用java.io.FileReader。

public class FileInputStream extends InputStream {

	private FileDescriptor fd;

	private FileChannel channel = null;

	// 调用参数为File的构造函数
	public FileInputStream(String name) throws FileNotFoundException {
		this(name != null ? new File(name) : null);
	}

	// 获取文件的路径并检查权限
	// 实例化FileDescriptor并赋给fd
	// 打开文件(native方法)
	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();
		}
		fd = new FileDescriptor();
		open(name);
	}

	// 检查权限和输入是否为空
	// 把参数对象赋给fd
	public FileInputStream(FileDescriptor fdObj) {
		SecurityManager security = System.getSecurityManager();
		if (fdObj == null) {
			throw new NullPointerException();
		}
		if (security != null) {
			security.checkRead(fdObj);
		}
		fd = fdObj;
	}

	// 根据文件名打开指定的文件
	private native void open(String name) throws FileNotFoundException;

	// 读取1个字节的数据,如果没有输入,则该方法阻断
	public native int read() throws IOException;

	// 从off位置开始,读取len长度字节的数据到字节数组b中
	private native int readBytes(byte b[], int off, int len) throws IOException;

	// 读取所有的字节到字节数组b中,如果输入不可用,则该方法阻断
	public int read(byte b[]) throws IOException {
		return readBytes(b, 0, b.length);
	}

	// 读取len长度的字节到字节数组b中,如果len不为0并且输入不可用,则该方法阻断,如果为0则返回0
	public int read(byte b[], int off, int len) throws IOException {
		return readBytes(b, off, len);
	}

	// 从输入流中跳过并丢弃 n 个字节的数据。
	//出于各种原因,skip 方法最终跳过的字节数可能更少一些,甚至可能为 0。如果 n 为负,则抛出 IOException,即使 InputStream 超类的 skip 方法在这种情况下没有执行任何操作。返回实际跳过的字节数。 
	//此方法跳过的字节可能多于底层文件中剩余的字节。这不会产生异常,并且跳过的字节数可能包括底层文件的 EOF(文件结束符)之后的一些字节数。如果试图在跳过末尾之后读取流,那么会返回指示文件末尾的 -1。 
	public native long skip(long n) throws IOException;

	// 返回下一次对此输入流调用的方法可以不受阻塞地从此输入流读取(或跳过)的估计剩余字节数。
	// 在某些情况下,非阻塞的读取(或跳过)操作在执行很慢时看起来受阻塞,例如,在网速缓慢的网络上读取大文件时
	public native int available() throws IOException;

	// 关闭流并且释放所有和这个流关联的系统资源
	public void close() throws IOException {
		if (channel != null)
			channel.close();
		close0();
	}

	// 返回表示到文件系统中实际文件的连接的FileDescriptor对象,该文件正被当前的FileInputStream实例所使用
	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, true, false, this);
			return channel;
		}
	}

	private static native void initIDs();

	private native void close0() throws IOException;

	static {
		initIDs();
	}

	// 确保没有对象和当前流关联时,调用close()方法来释放资源
	protected void finalize() throws IOException {
		if (fd != null) {
			if (fd != fd.in) {
				close();
			}
		}
	}
}
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics