Java InputStream&FileInputStream 源代码分析

在java输入流中,InputStream是一个抽象接口,主要实现了read(byte b[],int off,int len)方法,这个方法的实现依赖于read()抽象方法,也就是说,read主要还是依赖于子类的实现。这个方法主要作用是从文件中读取字节数,将其放入到byte数组中。看一下这个方法的实现:

public int read(byte b[], int off, int len) throws IOException {
        if (b == null) {
            throw new NullPointerException();
        } else if (off < 0 || len < 0 || len > b.length - off) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return 0;
        }

        int c = read();
        if (c == -1) {
            return -1;
        }
        b[off] = (byte)c;

        int i = 1;
        try {
            for (; i < len ; i++) {
                c = read();
                if (c == -1) {
                    break;
                }
                b[off + i] = (byte)c;
            }
        } catch (IOException ee) {
        }
        return i;
    }

这里可以看到read()才是实现读取的关键操作。再看一下read的定义

public abstract int read() throws IOException;

现在来看看FileInputStream的实现。这个类继承了InputStream,主要的字段包含如下几个:

private final FileDescriptor fd;
private final Object closeLock = new Object();
private volatile boolean closed = false;

第一个是文件描述符,用于描述一个打开的连接。第二个是一个锁对象,用于多线程管理。第三个是描述的文件流是否关闭状态。
构造函数主要如下:

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();
        fd.incrementAndGetUseCount();
        open(name);
    }

构造函数的主要作用是创建了一个文件描述符,并使用本地方法打开了这个文件。
这个类的本地方法有如下这些:

private native void open(String name) throws FileNotFoundException;
public native int read() throws IOException;

这里可以看到,打开,读取文件都是使用了本地方法。看一下close方法:

public void close() throws IOException {
        synchronized (closeLock) {
            if (closed) {
                return;
            }
            closed = true;
        }
        if (channel != null) {
            /*
             * Decrement the FD use count associated with the channel
             * The use count is incremented whenever a new channel
             * is obtained from this stream.
             */
           fd.decrementAndGetUseCount();
           channel.close();
        }

        /*
         * Decrement the FD use count associated with this stream
         */
        int useCount = fd.decrementAndGetUseCount();

        /*
         * If FileDescriptor is still in use by another stream, the finalizer
         * will not close it.
         */
        if ((useCount <= 0) || !isRunningFinalize()) {
            close0();
        }
    }

这个方法主要逻辑是,使用锁对象来进行同步,同时设置关闭状态为true。最后通过文件系统的文件描述符来进行操作。close0()方法也是本地的。

需要说明的是,在这里已经开始支持了NIO了,因为这里可以通过getChannel方法获取到FileChannel对象了。具体逻辑在分析NIO源代码时再说。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值