问题
I need to access numbered file descriptors from Java -- other than 0, 1 or 2.
How can this be done? I looked at the FileDescriptor class but did'nt find any way to initialize it with a given file descriptor number.
As a concrete example lets suppose Java gets called as a child process from another programing language. File descriptors 3 and 4 are provided by the other language for input and output.
What I need in Java are InputStream and OutputStream objects connected to these file-descriptors, just like System.in, System.out and System.error are connected to file-desctiptors 0, 1 and 2.
I'm using Java 1.6 and this should run on Unix alike systems.
Tested working solution:
The answer with the file descriptor special filesystem entries did point me to the following workable solution:
find out if and where your Unix alike system has a special filesystem that contains named entries for all file descriptors.
- I'm using FreeBSD where fdescfs(5) is a filesystem that does just this. Under Linux it would be procfs.
make sure this filesystem is mounted
FreeBSD: put
fdescfs /dev/fd fdescfs rw 0 0in/etc/fstabor run
mount -t fdescfs null /dev/fdon a shell prompt (probably with sudo)
Use new
FileInputStream("/dev/fd/3")andnew FileOutputStream("/dev/fd/4")to get the streams connected to the filedescriptors (the paths are for FreeBSD, replace with your operating systems paths)
回答1:
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.
回答2:
With a SUN JavaVM you can do:
FileDescriptor fd = new FileDescriptor();
sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess().set(fd,3);
FileInputStream fin = new FileInputStream(fd);
回答3:
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.
回答4:
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.
来源:https://stackoverflow.com/questions/4845122/using-a-numbered-file-descriptor-from-java