设计模式系列竣事,迎来了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)的地点偏移量。