我需要从Java访问编号的文件描述符 - 除了0,1或2。
如何才能做到这一点?我查看了qazxsw poi类,但没有找到任何方法用给定的文件描述符编号初始化它。
作为一个具体的例子,假设Java从另一个编程语言被调用为子进程。文件描述符3和4由另一种语言提供,用于输入和输出。
我在Java中需要的是连接到这些文件描述符的FileDescriptor
和InputStream
对象,就像System.in,System.out和System.error连接到文件解析器0,1和2一样。
我正在使用Java 1.6,这应该在类似Unix的系统上运行。
经过测试的工作方案:
文件描述符特殊文件系统条目的答案确实指向了以下可行的解决方案:
OutputStream
是一个文件系统就是这样做的。在Linux下它将是procfs。fdescfs /dev/fd fdescfs rw 0 0
或者在shell提示符下运行/etc/fstab
(可能带有sudo)mount -t fdescfs null /dev/fd
和FileInputStream("/dev/fd/3")
来获取连接到filedescriptors的流(路径适用于FreeBSD,替换为您的操作系统路径)我很确定使用纯Java无法做到这一点 - 您可能必须使用本机代码将文件描述符绑定到FileDescriptor对象或FileInputStream或FileOutputStream对象。
编辑 如果您使用的是Linux,* BSD或macOS,则可以使用伪文件/ dev / fd / nnn来访问文件描述符nnn。
使用SUN JavaVM,您可以:
new FileOutputStream("/dev/fd/4")
我最近需要为在监狱中运行的Java子进程执行此操作。这意味着它无法访问/ dev / fd文件系统。
@Bozho评论说,反射可能会或可能不会创建FileDescriptor对象。不过,它似乎在我做过的简单测试中起作用。以下是TestFD.java的源代码:
FileDescriptor fd = new FileDescriptor();
sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess().set(fd,3);
FileInputStream fin = new FileInputStream(fd);
为了测试这个,我制作了一个简单的Bash脚本来编译它,设置fd3,然后运行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());
}
}
果然,fd3被重定向到stdout,并在终端输出“hi there \ n”。注释掉“exec 3>&1”行,Java程序按预期失败,并显示“未配置设备”IOException。
对于私有FileDescriptor构造函数的反射似乎在无法访问/ dev / fd的情况下工作正常,并且比尝试使用JNI创建FileDescriptor更不笨,这是我在其他地方看到的一个建议。
注意:我在BSD系统上测试了这个。它可能适用于其他系统,也可能不适用。
首先:
应用程序不应创建自己的文件描述符
您可以尝试使用反射来调用构造函数#!/bin/bash
javac TestFD.java
exec 3>&1 # open fd3, redirect to stdout
java TestFD
exec 3>&-
,方法是获取构造函数并在其上调用private FileDescriptor(int fd)
。但这是一个黑客,我不能保证它会工作(它可能不会)。特别是考虑到我开始的报价。