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源代码时再说。

你可能感兴趣的:(java)