FileInputStream、FileOutputStream、SocketInputStream、SocketOutputStream中都有一个FileDescriptor对象,我们可以将这个文件描述符对象类比为我们要操作的文件在JVM中的一个句柄,但是这个句柄并没有实际对文件进行操作的动作,要想读取或者写入文件只能创建对象的输入流和输出流对象,FileDescriptor在输入输出流对象当中,他们是结合在一起的,如果只有一个FileDescriptor实例,而两个InputStream想从这个文件描述符对应的同一个文件中读取数据,那么就需要持有同一个FileDescriptor对象,输入也是一样,FileInputStream、FileOutputStream都对应的提供了通过FileDescriptor对象实例化的构造方法。
FileDescriptor类有一个useCount的属性,定义如下:
private AtomicInteger useCount;
这个字段就是记录当前有多少了输入输出流对象关联了这个FileDescriptor对象,当我们调用FileInputStream、FileOutputStream的close方法是close方法时,首先将useCount减1,然后做了一个判断,代码如下:
if ((useCount <= 0) || !isRunningFinalize()) {
close0();
}
如果当前useCount对象的值已经小于等于0的时候才会真正执行native的系统调用,关闭这个文件。
FileInputStream、FileOutputStream最底层的native的方法中,并没有看到对FileDescriptor的引用,而在上文SocketInputStream、SocketOutputStream对象对应的native调用方法中都提供了FileDescriptor对象的引用,
实际上这个在JDK以前的版本中是存在为FileDescriptor的一个long类型的名称为handle的字段,注意再FileInputStream、FileOutputStream中都有一下这么一段代码,而FileDescriptor也存在一个initIDs方法,都是在已静态代码块的形式存在的,他们的作用是相同的,就是设置属性的内存地址偏移量,FileInputStream的initIDs方法只设置了fd这一个属性的内存地址偏移量,FileDescriptor设置了两个属性(fd和handle)的内存地址偏移量。
private static native void initIDs();
static {