Using a numbered file descriptor from Java

余生长醉 提交于 2019-12-02 20:42:21

I'm pretty sure this can't be done using pure Java -- you'll probably have to use native code to bind a file descriptor to a FileDescriptor object or a FileInputStream or FileOutputStream object.

EDIT
If you're using Linux, *BSD or macOS, you can use the pseudo files /dev/fd/nnn to access file-descriptor nnn.

paf.goncalves

With a SUN JavaVM you can do:

FileDescriptor fd = new FileDescriptor();
sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess().set(fd,3);
FileInputStream fin = new FileInputStream(fd);

I recently needed to do this for a Java child process running in a jail. This meant it did not have access to the /dev/fd filesystem.

@Bozho made a comment that reflection may or may not work to create a FileDescriptor object. It appears to work in a simple test I did, though. The following is source for TestFD.java:

import java.lang.reflect.Constructor;
import java.io.FileDescriptor;
import java.io.FileOutputStream;

public class TestFD {
  public static void main(String[] args) throws Exception {
    Constructor<FileDescriptor> ctor = FileDescriptor.class.getDeclaredConstructor(Integer.TYPE);
    ctor.setAccessible(true);
    FileDescriptor fd = ctor.newInstance(3);
    ctor.setAccessible(false);

    new FileOutputStream(fd).write("hi there\n".getBytes());
  }
}

To test this, I made a simple Bash script that compiles it, sets up fd3, and runs the java program:

#!/bin/bash

javac TestFD.java

exec 3>&1  # open fd3, redirect to stdout
java TestFD
exec 3>&-

Sure enough, fd3 is redirected to stdout, and outputs "hi there\n" on the terminal. Comment out the "exec 3>&1" line and the Java program fails as expected with a "Device not configured" IOException.

Reflection on the private FileDescriptor constructor seems to work fine in cases where access to /dev/fd is not possible, and is less clunky than trying to create a FileDescriptor using JNI, a suggestion that I have seen elsewhere.

Note: I tested this on a BSD system. It may or may not work on other systems.

To begin with:

Applications should not create their own file descriptors

You can try using reflection to invoke the constructor private FileDescriptor(int fd), by obtaining the constructor and calling setAccessible(true) on it. But that's a hack and I can't guarantee it will work (it's likely that it won't). Especially given the quote I started with.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!