POSIX标准
先了解一下POSIX标准,POSIX标准是操作系统为应用程序提供的接口,是电子和电气工程协会(简称IEEE)为要在各种UNIX操作系统上运行软件而定义的一系列API标准总称,目的是为了保证应用程序的可移植性.也就是说为一个POSIX操作系统编写的应用程序,在另外一个POSIX操作系统里面依旧可以运行.比如:POSIX标准接口:Open()打开文件,create()创建文件,read()读取文件,write()写入文件等接口,如果在以POSIX标准的操作系统编写的应用程序调用到了Open()接口(操作系统提供接口),那么应用程序移植到别的以POSIX标准的操作系统,同样也可以运行.因为调用操作系统接口都是一样的.都是Open().
文件描述符
对内核而言,所有打开的文件(或者socket)都是由文件描述符引用,打开一个现存的文件或者是创建一个新文件时,内核会向当前进程返回一个文件描述符,那么根据文件描述符就可以找到对应的文件。比如读写一个文件的简单步骤:
文件描述符是一个非负的整数,在POSIX标准的应用程序中,整数0,1,2分别表示的是标准输入,标准输出,标准错误输出的描述符.最早期的UNIX版本中最大值是19(也就是容许每个进程打开20个文件),现在系统都有所增加,比如Linux是1024,在java中虽然设计使用的是抽象度更高的流,但是依然需要文件描述符与操作系统进行交互.
在java中FileDescriptor表示的是"文件描述符",对于文件描述符中0,1,2分别表示如下:
整数值 | 名称 |
0 | 标准输入描述符 |
1 |
标准输出描述符 |
2 | 标准错误输出描述符 |
对于三个"文件描述符",用法基本上是相似的.比如标准输出描述符,看FileDescriptor源码,调用的方式是FileDescriptor.out.但是由于FileDescriptor没有直接输出屏幕的接口,需要借助输出流对象,通过调用输出流的方法write()方法,可以将对应的字符输出到控制台上,案例如下:
public class FileDescriptorDemo {
public static void main(String[] args) throws Exception {
FileOutputStream fos = new FileOutputStream(FileDescriptor.out);
fos.write("abcd".getBytes());
fos.close();
}
}
运行的结果是:
abcd
当然在java中已经有相应封装的接口,可以直接输出到控制台:System.out.println("abcd").其余标准输入描述符对应是System.in,而标准错误输出对应的是System.err.
public final class FileDescriptor {
//打开的文件或者socket时,简单说操作系统会返回一个fd值,通过该值可以对文件,socket等进行相关操作,
private int fd;
//关联的流只有一个,则保存到parent中
private Closeable parent;
//关联的流很多,则保存到集合otherParents中
private List otherParents;
//用于判断是否释放文件文件引用
private boolean closed;
//无参数构造方法,fd赋值为-1, 由于java中文件描述符是大于0的整数,所以无意义.
public FileDescriptor() {
fd = -1;
}
//有参构造方法,由于修饰符是private,无法设置fd
private FileDescriptor(int fd) {
this.fd = fd;
}
//标准的输入,文件描述符用0表示
public static final FileDescriptor in = new FileDescriptor(0);
//标准的输出,文件描述符用1表示
public static final FileDescriptor out = new FileDescriptor(1);
//标准错误输出,文件描述符用2表示
public static final FileDescriptor err = new FileDescriptor(2);
//判断是否有效,非-1有效.所以无参构造方法中fd=-1无效
public boolean valid() {
return fd != -1;
}
public native void sync() throws SyncFailedException;
/* This routine initializes JNI field offsets for the class */
private static native void initIDs();
static {
initIDs();
}
// Set up JavaIOFileDescriptorAccess in SharedSecrets
static {
sun.misc.SharedSecrets.setJavaIOFileDescriptorAccess(
new sun.misc.JavaIOFileDescriptorAccess() {
public void set(FileDescriptor obj, int fd) {
obj.fd = fd;
}
public int get(FileDescriptor obj) {
return obj.fd;
}
public void setHandle(FileDescriptor obj, long handle) {
throw new UnsupportedOperationException();
}
public long getHandle(FileDescriptor obj) {
throw new UnsupportedOperationException();
}
}
);
}
//会将文件描述符相关的流添加到otherParents集合中.
//结合下面closeAll()方法,释放文件描述符的引用,同时也会将对应所有的流关闭
//因为文件描述符释放的情况下,流的存在也无意义
synchronized void attach(Closeable c) {
if (parent == null) {
// first caller gets to do this
parent = c;
} else if (otherParents == null) {
otherParents = new ArrayList<>();
otherParents.add(parent);
otherParents.add(c);
} else {
otherParents.add(c);
}
}
//关闭所有与文件描述符关联的所有的流对象
@SuppressWarnings("try")
synchronized void closeAll(Closeable releaser) throws IOException {
if (!closed) {
closed = true;
IOException ioe = null;
try (Closeable c = releaser) {
if (otherParents != null) {
for (Closeable referent : otherParents) {
try {
referent.close();
} catch(IOException x) {
if (ioe == null) {
ioe = x;
} else {
ioe.addSuppressed(x);
}
}
}
}
} catch(IOException ex) {
if (ioe != null)
ex.addSuppressed(ioe);
ioe = ex;
} finally {
if (ioe != null)
throw ioe;
}
}
}
}
总结:
1.文件描述符就是打开文件或socket时,操作系统返回的一个int类型值.会根据文件描述符结合流操作对应的文件或者socket.
2.文件描述符是一个非负的整数,其中0,1,2分别表示的标准输入,标准输出和标准错误输出.在java中已经有相关接口封装,分别是System.in;System.out;System.err.