JDK源码(十):FileInputStream

 

FileInputStream从文件系统中的文件获取输入字节。哪些文件可用取决于主机环境,FileInputStream用于读取原始字节流,如图像数据。要读取字符流,请考虑使用FileReader。

public class FileInputStreamDemo {

    public static void main(String[] args) throws IOException {

        FileInputStream inputStream =
                new FileInputStream("D:\\jdk_s_d\\out.txt");

        byte[] bytes = new byte[1024];
        int len;
        while ((len = inputStream.read(bytes)) != -1){
            String str = new String(bytes,0, len);
            System.out.println(str);
        }
        inputStream.close();
    }
}

    在创建一个FileInputStream文件输入流时,主要做了两件事,一个是new一个FileDescriptor(文件描述符),一个便是调用了open方法。

      不过在此之前,还调用了一个方法,在FileInputStream源码的下方,有这样一个静态块。


private static native void initIDs();
static {
    initIDs();
}

它的作用是设置类中(也就是FileInputStream)的属性的内存地址偏移量,便于在必要时操作内存给它赋值,而FileInputStream的initIDs方法只设置了fd这一个属性的内存地址偏移量。

源码(1.8)

/**
 * @since   JDK1.0
 */
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;
    /**
     * 通过打开与实际文件的连接,创建FileInputStream。
	 * 将创建一个新的FileDescriptor对象来表示此文件连接
     * <p>
     * 如果有一个安全管理器,会把name作为参数调用它的checkRead方法
     * <p>
     * 如果命名文件不存在,是一个目录而不是一个常规文件,
	 * 或者由于其他原因无法打开读取,则抛出FileNotFoundException.
	 * FileInputStream inputStream = 
	 *                  new FileInputStream("D:\\jdk_s_d\\out.txt");
     */
    public FileInputStream(String name) throws FileNotFoundException {
		//调用下面的FileInputStream(File file)
        this(name != null ? new File(name) : null);
    }
    /**
	 * FileInputStream inputStream = 
	 *               new FileInputStream(new File("D:\\jdk_s_d\\out.txt");
     */
    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上安装一个Closeable进行跟踪。
		//需要时将父引用添加到其他父引用,以简化closeAll
        fd.attach(this);
        path = name;
        open(name);
    }
    /**
     * 使用FileDescriptor创建FileInputStream
     * <p>
     */
    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);
    }
    /**
     * 打开指定文件进行读取
     */
    private native void open0(String name) throws FileNotFoundException;
    /**
     * 打开指定文件进行读取
     */
    private void open(String name) throws FileNotFoundException {
        open0(name);
    }
    /**
     * 从这个输入流中读取一个字节的数据。
	 * 如果还没有可用的输入,则此方法将阻塞
     * @return 数据的下一个字节,如果到达文件末尾,则为-1.
     */
    public int read() throws IOException {
        return read0();
    }
    private native int read0() throws IOException;
    /**
     * 以字节序列的形式读取子数组.
     * @param b 将数据读入b[]中
     * @param off 从b[off]开始
     * @param len 要读入的长度
     */
    private native int readBytes(byte b[], int off, int len) 
	                                            throws IOException;
    public int read(byte b[]) throws IOException {
        return readBytes(b, 0, b.length);
    }
    /**
     * 调用readBytes方法
     */
    public int read(byte b[], int off, int len) throws IOException {
        return readBytes(b, off, len);
    }
    /**
     * 跳过n个字节数据
     */
    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();
           }
        });
    }
    /**
     * 返回当前的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();
    }
    /**
     * 确保在不在引用该文件输入流时调用该文件输入流的close方法.
     */
    protected void finalize() throws IOException {
        if ((fd != null) &&  (fd != FileDescriptor.in)) {
            /* 如果fd是共享的,那么FileDescriptor中的
			* 引用将确保只在安全的情况下调用finalizer。
			* 使用fd的所有引用都变得不可访问。
			* 我们可以调用close()
             */
            close();
        }
    }
}

更多精彩内容请关注微信公众号:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

徐楠_01

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值