FileDescriptor是文件描述符,可以被用来表示开放文件,开放套接字等,FileDescriptor可以被看成某个文件,但无法对该文件进行操作,需要新创建FileDescriptor对应的FileOutputStream再对文件进行操作。
FileDescriptor示例代码:
public class FileDescriptorTest { private static final String FileName = "file.txt"; private static final String OutText = "Hi FileDescriptor"; public static void main(String[] args) { testWrite(); testRead(); testStandFD() ; //System.out.println(OutText); } /** * FileDescriptor.out 的测试程序 * 该程序的效果 等价于 System.out.println(OutText); */ private static void testStandFD() { // 创建FileDescriptor.out 对应的PrintStream PrintStream out = new PrintStream(new FileOutputStream(FileDescriptor.out)); // 在屏幕上输出“Hi FileDescriptor” out.println(OutText); out.close(); } /** * FileDescriptor写入示例程序 * (01) 为了说明,"通过文件名创建FileOutputStream"与“通过文件描述符创建FileOutputStream”对象是等效的 * (02) 该程序会在“该源文件”所在目录新建文件"file.txt",并且文件内容是"Aa"。 */ private static void testWrite() { try { // 新建文件“file.txt”对应的FileOutputStream对象 FileOutputStream out1 = new FileOutputStream(FileName); // 获取文件“file.txt”对应的“文件描述符” FileDescriptor fdout = out1.getFD(); // 根据“文件描述符”创建“FileOutputStream”对象 FileOutputStream out2 = new FileOutputStream(fdout); out1.write('A'); // 通过out1向“file.txt”中写入'A' out2.write('a'); // 通过out2向“file.txt”中写入'A' if (fdout!=null) System.out.printf("fdout(%s) is %s\n",fdout, fdout.valid()); out1.close(); out2.close(); } catch(IOException e) { e.printStackTrace(); } } /** * FileDescriptor读取示例程序 * * 为了说明,"通过文件名创建FileInputStream"与“通过文件描述符创建FileInputStream”对象是等效的 */ private static void testRead() { try { // 新建文件“file.txt”对应的FileInputStream对象 FileInputStream in1 = new FileInputStream(FileName); // 获取文件“file.txt”对应的“文件描述符” FileDescriptor fdin = in1.getFD(); // 根据“文件描述符”创建“FileInputStream”对象 FileInputStream in2 = new FileInputStream(fdin); System.out.println("in1.read():"+(char)in1.read()); System.out.println("in2.read():"+(char)in2.read()); if (fdin!=null) System.out.printf("fdin(%s) is %s\n", fdin, fdin.valid()); in1.close(); in2.close(); } catch(IOException e) { e.printStackTrace(); } } }
运行结果:
fdout(java.io.FileDescriptor@1ea21c07) is true
in1.read():A
in2.read():a
fdin(java.io.FileDescriptor@24de1f47) is true
Hi FileDescriptor
in1.read():A
in2.read():a
fdin(java.io.FileDescriptor@24de1f47) is true
Hi FileDescriptor
基于JDK8的FileDescriptor的源码:
public final class FileDescriptor { private int fd; private long handle; private Closeable parent; private List<Closeable> otherParents; private boolean closed; /** * Constructs an (invalid) FileDescriptor * object. */ public /**/ FileDescriptor() { fd = -1; handle = -1; } 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) { obj.handle = handle; } public long getHandle(FileDescriptor obj) { return obj.handle; } } ); } /** * 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}. * * @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}. * @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}. * * @see java.lang.System#err */ //标准错误 public static final FileDescriptor err = standardStream(2); /** * Tests if this file descriptor object is valid. * * @return {@code true} if the file descriptor object represents a * valid, open file, socket, or other active I/O connection; * {@code false} otherwise. */ //文件描述对象是否有效 public boolean valid() { return ((handle != -1) || (fd != -1)); } /** * Force all system buffers to synchronize with the underlying * device. This method returns after all modified data and * attributes of this FileDescriptor have been written to the * relevant device(s). In particular, if this FileDescriptor * refers to a physical storage medium, such as a file in a file * system, sync will not return until all in-memory modified copies * of buffers associated with this FileDesecriptor have been * written to the physical medium. * * sync is meant to be used by code that requires physical * storage (such as a file) to be in a known state For * example, a class that provided a simple transaction facility * might use sync to ensure that all changes to a file caused * by a given transaction were recorded on a storage medium. * * sync only affects buffers downstream of this FileDescriptor. If * any in-memory buffering is being done by the application (for * example, by a BufferedOutputStream object), those buffers must * be flushed into the FileDescriptor (for example, by invoking * OutputStream.flush) before that data will be affected by sync. * * @exception SyncFailedException * Thrown when the buffers cannot be flushed, * or because the system cannot guarantee that all the * buffers have been synchronized with physical media. * @since JDK1.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; } /* * Package private methods to track referents. * If multiple streams point to the same FileDescriptor, we cycle * through the list of all referents and call close() */ /** * Attach a Closeable to this FD for tracking. * parent reference is added to otherParents when * needed to make closeAll simpler. */ 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); } } /** * Cycle through all Closeables sharing this FD and call * close() on each one. * * The caller closeable gets to call close0(). */ @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 releaser close() throws IOException * add other exceptions as suppressed. */ if (ioe != null) ex.addSuppressed(ioe); ioe = ex; } finally { if (ioe != null) throw ioe; } } } }