Using a numbered file descriptor from Java
Solution 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.
Solution 2
With a SUN JavaVM you can do:
FileDescriptor fd = new FileDescriptor();
sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess().set(fd,3);
FileInputStream fin = new FileInputStream(fd);
Solution 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.
Solution 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.
Related videos on Youtube
Peer Stritzinger
Updated on August 28, 2021Comments
-
Peer Stritzinger almost 3 years
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
andOutputStream
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.
-
Admin over 13 yearskfu.com/~nsayer/Java/jni-filedesc.html might help
-
Charles Duffy almost 3 yearsYour working solution should be in an answer, not as part of the question.
-
-
Peer Stritzinger over 13 yearsMy problem is that these file descriptors I get passed are a given by the runtime of the other language and other external constraints I have no influence in. So the need for this is not by my choice. I'll try your suggestion for the hack.
-
Peer Stritzinger over 13 yearsAs you suspected ... it won't work. I can only get public constructors via Class.getConstructor
-
Bozho over 13 years@Peer Stritzinger - use
FileDescriptor.getDeclaredConstructor(..)
-
Peer Stritzinger over 13 yearsYeah when learning from your answers that this isn't possible in Java itself (which I didn't dream of) I was looking into operating system support for it. I'm running under FreeBSD and have /dev/fd/<nnn> for all open file descriptors.
-
Philippe Marschall over 6 yearsThis is unsupported, not API and will break with Java 9.
-
FThompson over 6 yearsThis does not work on Windows, as the only constructor is the default one.
-
ctrl-alt-delor almost 6 yearsIt is a perfectly valid thing to open a raw file-descriptor. How else can a parent process pass a file.
-
Corrodias over 4 yearsThen, is there a similar approach for newer versions of Oracle HotSpot? What about in OpenJDK?
-
Scott Tiger about 2 yearsWorks on Linux like a charm.