使用Java编号的文件描述符

我需要从Java访问编号的文件描述符 – 除了0,1或2。

如何才能做到这一点? 我查看了FileDescriptor类,但没有找到任何方法用给定的文件描述符编号初始化它。

作为一个具体的例子,假设Java从另一个编程语言被调用为子进程。 文件描述符3和4由另一种语言提供,用于输入和输出。

我在Java中需要的是连接到这些文件描述符的InputStreamOutputStream对象,就像System.in,System.out和System.error连接到文件解析器0,1和2一样。

我正在使用Java 1.6,这应该在类似Unix的系统上运行。

经过测试的工作方案:

文件描述符特殊文件系统条目的答案确实指向了以下可行的解决方案:

  1. 找出你的Unix系统是否以及在哪里有一个包含所有文件描述符的命名条目的特殊文件系统。

    • 我正在使用FreeBSD,其中fdescfs(5)是一个文件系统就是这样做的。 在Linux下它将是procfs。
  2. 确保已安装此文件系统

    • FreeBSD:在/etc/fstab放入fdescfs /dev/fd fdescfs rw 0 0

      或者在shell提示符下运行mount -t fdescfs null /dev/fd (可能带有sudo)

  3. 使用新的FileInputStream("/dev/fd/3")new FileOutputStream("/dev/fd/4")来获取连接到文件描述符的流(路径用于FreeBSD,替换为您的操作系统路径)

我很确定使用纯Java无法做到这一点 – 您可能必须使用本机代码将文件描述符绑定到FileDescriptor对象或FileInputStream或FileOutputStream对象。

编辑
如果您使用的是Linux,* BSD或macOS,则可以使用伪文件/ dev / fd / nnn来访问文件描述符nnn。

使用SUN JavaVM,您可以:

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

我最近需要为在监狱中运行的Java子进程执行此操作。 这意味着它无法访问/ dev / fd文件系统。

@Bozho评论说reflection可能会或可能不会创建FileDescriptor对象。 不过,它似乎在我做过的简单测试中起作用。 以下是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 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()); } } 

为了测试这个,我制作了一个简单的Bash脚本来编译它,设置fd3,然后运行java程序:

 #!/bin/bash javac TestFD.java exec 3>&1 # open fd3, redirect to stdout java TestFD exec 3>&- 

果然,fd3被重定向到stdout,并在终端上输出“hi there \ n”。 注释掉“exec 3>&1”行,Java程序按预期失败,并显示“未配置设备”IOException。

对于私有FileDescriptor构造函数的reflection似乎在无法访问/ dev / fd的情况下工作正常,并且比尝试使用JNI创建FileDescriptor更不笨,这是我在别处看到的一个建议。

注意:我在BSD系统上测试了这个。 它可能适用于其他系统,也可能不适用。

首先:

应用程序不应创建自己的文件描述符

您可以尝试使用reflection来调用构造函数private FileDescriptor(int fd) ,方法是获取构造函数并在其上调用setAccessible(true) 。 但这是一个黑客,我不能保证它会工作(它可能不会)。 特别是考虑到我开始的报价。