设计模式系列竣事,迎来了LZ第一篇关于JAVA虚拟机的文章,这一系列文章不再像之前的设计模式一样,有着严格的约束力,本系列文章相对会较量随性,本次LZ就跟列位分享一个关于FileInputStream的小奥秘。
在探究这个奥秘之前,列位假如没有openjdk的源码,可以去LZ的资源先下载下来,链接是:JVM源码 和 JDK源码
由于资源有最大60MB的限制,所以LZ分成了两部门,一个是JVM的源码,一个是JDK中的源码,而当处所法的源码都在JDK的谁人压缩包傍边,全部源码下载在openjdk的官网上也有,列位也可以去哪里找一下,假如嫌贫苦的话,就去LZ的资源里下载即可。
此刻源码我们已经有了,可以来看下我们研究的小奥秘了。各人都知道我们在读取文件时离不开FileInputStream这个类,那么不知道列位有没有好奇过,我们的FileInputStream是如何成立的呢?
我们一起先来看看FileInputStream的源码,我们平时都是通过new FileInputStream(name or File)的方法获得的文件输入流,所以我们来看FileInputStream的结构要领。
public class FileInputStream extends InputStream { /* File Descriptor - handle to the open file */ private FileDescriptor fd; private FileChannel channel = null; 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(); } fd = new FileDescriptor(); open(name); }
我们忽略安详打点器的查抄,可以看到,在建设一个文件输入流时,主要做了两件事,一个是new一个FileDescriptor(文件描写符),一个即是挪用了open要领。
不外在此之前,其实还挪用了一个要领,在FileInputStream源码的下方,有这样一个静态块。
static { initIDs(); }
它将在第一次加载FileInputStream类的时候,挪用一个静态的initIDs的当处所法,这里我们不跟踪这个要领的源码,它并不是我们的重点,它的浸染是配置类中(也就是FileInputStream)的属性的地点偏移量,便于在须要时操纵内存给它赋值,而FileInputStream的initIDs要领只配置了fd这一个属性的地点偏移量。
接下来,我们首先看下FileDescriptor这个类是什么样子的,它的源码如下。
package java.io; public final class FileDescriptor { private int fd; private long handle; /** * Constructs an (invalid) FileDescriptor * object. */ public /**/ FileDescriptor() { fd = -1; handle = -1; } private /* */ FileDescriptor(int fd) { this.fd = fd; handle = -1; } static { initIDs(); } /** * A handle to the standard input stream. Usually, this file * descriptor is not used directly, but rather via the input stream * known as <code>System.in</code>. * * @see java.lang.System#in */ public static final FileDescriptor in = standardStream(0); /** * A handle to the standard output stream. Usually, this file * descriptor is not used directly, but rather via the output stream * known as <code>System.out</code>. * @see java.lang.System#out */ public static final FileDescriptor out = standardStream(1); /** * A handle to the standard error stream. Usually, this file * descriptor is not used directly, but rather via the output stream * known as <code>System.err</code>. * * @see java.lang.System#err */ public static final FileDescriptor err = standardStream(2); /** * Tests if this file descriptor object is valid. * * @return <code>true</code> if the file descriptor object represents a * valid, open file, socket, or other active I/O connection; * <code>false</code> otherwise. */ public boolean valid() { return ((handle != -1) || (fd != -1)); } public native void sync() throws SyncFailedException; /* This routine initializes JNI field offsets for the class */ private static native void initIDs(); private static native long set(int d); private static FileDescriptor standardStream(int fd) { FileDescriptor desc = new FileDescriptor(); desc.handle = set(fd); return desc; } }
可以看到,这内里也有initIDs的静态块,它与FileInputStream中的静态块的浸染雷同,只不外这里配置了两个属性(fd和handle)的地点偏移量。