Java InputStream&FileInputStream 源代码分析

来源:互联网 发布:glibc malloc源码 编辑:程序博客网 时间:2024/05/02 07:05

在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
原创粉丝点击