文档章节

【Java部分源码分析之io篇】2.FileInputStream

gongwilliam
 gongwilliam
发布于 2017/07/26 17:03
字数 918
阅读 79
收藏 0

3 月,跳不动了?>>>

FileInputStream是继承于InputStream的其中一个子类,还有好多个子类继承于InputStream,因为FileInputStream在工程中用得比较多,所以特地拿一个典型出来分析一下。 先来看一下FileInputStream的成员变量。

    private final FileDescriptor fd;
    private final String path;
    private FileChannel channel = null;
    private final Object closeLock = new Object();
    private volatile boolean closed = false;

如果你对*unix文件编程有了解的话,对这个fd应该不陌生,fd就是文件描述符,它的作用就是用来唯一标记一个文件,可以这么说,只要拿到fd,就可以对相对应的文件进行操作。

path就是文件的路径。

channel是NIO的部分,这是NIO与IO的连接部分,看了一下源码,jdk1.4版本加入的功能。

closeLock是一个对象锁。在文件流关闭的时候用来判断是否可以关闭。下面的closed也是用来判断是否可以进行关闭文件。

FileInputStream有三个重载构造方法。

    public FileInputStream(String name) throws FileNotFoundException {
        this(name != null ? new File(name) : null);
    }
    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);
    }
    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);
    }

第一个构造方法主要是调用的第二个构造方法。

第二个构造方法是用一个File对象构造。代码先是对这个文件的读权限进行检查,然后获取这个文件的FD,路径,最后打开文件。

第三个是用一个文件描述符构造。步骤都差不多。

大家对这个 步骤也许有点疑惑,fd.attach(this);这个步骤主要是用来为以后的close做准备的,它会跟踪对这个FD的引用对象。

接下来就是重头戏read函数了。

    public int read() throws IOException {
        return read0();
    }
    private native int read0() throws IOException;
    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);
    }
    public int read(byte b[], int off, int len) throws IOException {
        return readBytes(b, off, len);
    }

可以看到涉及底层字节操作的方法都是在JVM层面上实现,read0和readBytes都是本地方法实现,问我怎么知道?请看native 关键字呀。

其他的重载方法都是在这两者的基础上进行扩展的。也很容易懂,read就是读取一个字节的内容,返回0-255之间的一个数值,如果读不到数据,则返回-1;read(数组)这个方法则是读取文件中数据到一个数组内。

    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();
           }
        });
    }

来看FileInputStream的close方法。这个方法有个同步块,所以在多线程环境下的close操作是安全的。最后的方法体中的close0是一个本地方法,具体实现在JVM层面上,应该就是释放系统资源之类的。

    public FileChannel getChannel() {
        synchronized (this) {
            if (channel == null) {
                channel = FileChannelImpl.open(fd, path, true, false, this);
            }
            return channel;
        }
    }

这个方法主要是获取一个FileChannel。

    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();
        }
    }

一般来说,类方法是很少有这个finalize方法的,这个方法主要在Object方法中实现,这里重写这个方法主要是为了防止GC的时候还有资源没有释放干净,在GC之前再次把引用的资源释放干净。

© 著作权归作者所有

gongwilliam
粉丝 2
博文 14
码字总数 12127
作品 0
深圳
私信 提问
加载中

评论(0)

泥沙砖瓦浆木匠/java-core-learning-example

感谢赞助的ta们 Java 核心系列教程,关于Java核心技术学习积累的例子,是初学者及核心技术巩固的最佳实践。 包括基础语法,OOP,字符串,集合,IO,反射,线程,网络等。 未完成模块:阿里J...

泥沙砖瓦浆木匠
2019/04/02
0
0
从1+1=2来理解Java字节码

背景 前不久《深入理解Java虚拟机》第三版发布了,赶紧买来看了看新版的内容,这本书更新了很多新版本虚拟机的内容,还对以前的部分内容进行了重构,还是值得去看的。本着复习和巩固的态度,...

木木匠
2019/12/30
6K
11
【目录导航】JAVA零基础进阶之路

【JAVA零基础入门系列】(已完结)导航目录 Day1 开发环境搭建 Day2 Java集成开发环境IDEA Day3 Java基本数据类型 Day4 变量与常量 Day5 Java中的运算符 Day6 Java字符串 Day7 Java输入与输出...

MFrank
2018/06/21
0
0
Java 208 道面试题:Java 基础模块答案

目前市面上的面试题存在两大问题:第一,题目太旧好久没有更新了,还都停留在 2010 年之前的状态;第二,近几年 JDK 更新和发布都很快,Java 的用法也变了不少,加上 Java 技术栈也加入了很多...

王磊的博客
2019/03/05
921
0
Java NIO原理 图文分析及代码实现

Java NIO原理图文分析及代码实现 前言: 最近在分析hadoop的RPC(Remote Procedure Call Protocol ,远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术...

囚兔
2015/04/29
349
1

没有更多内容

加载失败,请刷新页面

加载更多

JavaScript等同于printf / String.Format - JavaScript equivalent to printf/String.Format

问题: I'm looking for a good JavaScript equivalent of the C/PHP printf() or for C#/Java programmers, String.Format() ( IFormatProvider for .NET). 我正在寻找一个等效于C / PHP p......

javail
今天
27
0
什么是Android上的“上下文”? - What is 'Context' on Android?

问题: In Android programming, what exactly is a Context class and what is it used for? 在Android编程中, Context类到底是什么?它的用途是什么? I read about it on the developer......

技术盛宴
今天
26
0
OkHttp配置HTTPS访问+服务器部署

1 概述 OkHttp配置HTTPS访问,核心为以下三个部分: sslSocketFactory() HostnameVerifier X509TrustManager 第一个是ssl套接字工厂,第二个用来验证主机名,第三个是证书信任器管理类.通过OkHtt...

氷泠
今天
20
0
华为P40发布:搭载HMS硬刚谷歌,未涨价抢全球高端机市场

  文连线 Insight,作者向阳,编辑水笙   3 月 26 日晚,华为消费者业务 CEO 余承东登上台,以熟悉的英文口音开启了华为发布会,他说,“这就是我们的 P40 系列。”   以往华为P系列通...

水果黄瓜
今天
30
0
OSChina 周一乱弹 —— 小姐姐,这tm不是犬耳娘吗!你认错了吧

Osc乱弹歌单(2020)请戳(这里) 【今日歌曲】 @薛定谔的兄弟 :分享洛神有语创建的歌单「我喜欢的音乐」: 《Drip Drip Drip》- 音乐治疗 手机党少年们想听歌,请使劲儿戳(这里) @-Eric- ...

小小编辑
今天
96
1

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部