Using a numbered file descriptor from Java

12,394

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.

Share:
12,394

Related videos on Youtube

Peer Stritzinger
Author by

Peer Stritzinger

Updated on August 28, 2021

Comments

  • Peer Stritzinger
    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 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.

  • Peer Stritzinger
    Peer Stritzinger over 13 years
    My 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
    Peer Stritzinger over 13 years
    As you suspected ... it won't work. I can only get public constructors via Class.getConstructor
  • Bozho
    Bozho over 13 years
    @Peer Stritzinger - use FileDescriptor.getDeclaredConstructor(..)
  • Peer Stritzinger
    Peer Stritzinger over 13 years
    Yeah 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
    Philippe Marschall over 6 years
    This is unsupported, not API and will break with Java 9.
  • FThompson
    FThompson over 6 years
    This does not work on Windows, as the only constructor is the default one.
  • ctrl-alt-delor
    ctrl-alt-delor almost 6 years
    It is a perfectly valid thing to open a raw file-descriptor. How else can a parent process pass a file.
  • Corrodias
    Corrodias over 4 years
    Then, is there a similar approach for newer versions of Oracle HotSpot? What about in OpenJDK?
  • Scott Tiger
    Scott Tiger about 2 years
    Works on Linux like a charm.