获取FileChannel的Linux文件描述符



是否有办法获得打开的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。

最新更新