是否有办法获得打开的FileChannel的Linux文件描述符?
我需要它调用mount.fuse -o fd=...
(用于实现FUSE)。
作为一个hack的解决方案,我正在做:
var pid = ProcessHandle.current().pid();
var fd = Files.list(Path.of("/proc/"+pid+"/fd")).count();
var fc = FileChannel.open(path);
System.out.println("file descriptor: " + fd);
注意出现了两个文件描述符。一个是path
,一个是socket
。我用的是第一个。这个插座是干什么用的?
您可以使用反射从RandomAccessFile
获取文件描述符:
long pid = ProcessHandle.current().pid();
long guessedFd = Files.list(Path.of("/proc/"+pid+"/fd")).count();
var file = new java.io.RandomAccessFile(FUSE_DEVICE_PATH.toFile(), "rw");
FileChannel fc = file.getChannel(); // Use FileChannel for fast NIO
var javaFd = file.getFD();
try {
Field f = FileDescriptor.class.getDeclaredField("fd");
f.setAccessible(true);
var trueFd = (int) f.get(javaFd);
return trueFd;
}
catch (InaccessibleObjectException | NoSuchFieldException | IllegalAccessException e) {
return guessedFd;
}
在Java 11+上,您将在启动时设置jvm选项--add-opens=java.base/java.io=ALL-UNNAMED
。
在Java 17中,你可以使用SharedSecrets
来代替反射:
FileDescriptor javaFd = ...
try {
int trueFd = jdk.internal.access.SharedSecrets.getJavaIOFileDescriptorAccess().get(javaFd);
return trueFd;
}
catch (IllegalAccessError e) {
return guessedFd;
}
您需要在编译和运行时添加--add-exports=java.base/jdk.internal.access=ALL-UNNAMED
。参见Maven。