Reputation: 43
I have method, which using sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess().get(FileDescriptor)
by Java 8 for getting the real POSIX file descriptor. In Java 9 (and upper) SharedSecrets was migrated to jdk.internal.misc
.
How can I get POSIX file descriptor in Java 11?
private int getFileDescriptor() throws IOException {
final int fd = SharedSecrets.getJavaIOFileDescriptorAccess().get(getFD());
if(fd < 1)
throw new IOException("failed to get POSIX file descriptor!");
return fd;
}
Thanks in advance!
Upvotes: 2
Views: 785
Reputation: 91
To this I need to add that for newer versions of java you need to do this:
package demo;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
public class demo {
public static void main(String[] args) {
try {
var file = File.createTempFile("example-", ".log");
try (var fis = new FileInputStream(file)) {
var fd = fis.getFD();
var fieldName = "handle"; // For Windows.
if (!System.getProperty("os.name").toLowerCase().contains("windows")) {
fieldName = "fd"; // Other OS
}
var field = FileDescriptor.class.getDeclaredField(fieldName);
field.setAccessible(true);
var fdValue = field.get(fd);
field.setAccessible(false);
System.out.println(String.format("File: %s, %s: %s", file.getCanonicalPath(), fieldName, fdValue));
} catch (IOException | NoSuchFieldException | IllegalAccessException e) {
e.fillInStackTrace();
}
} catch (IOException e) {
e.fillInStackTrace();
}
}
}
And, in newer versions of java, running it requires adding the jvm arg.
Otherwise you get errors like this:
Exception in thread "main" java.lang.reflect.InaccessibleObjectException: Unable to make field private int java.io.FileDescriptor.fd accessible: module java.base does not "opens java.io" to unnamed module @6973bf95
at java.base/java.lang.reflect.AccessibleObject.throwInaccessibleObjectException(AccessibleObject.java:388)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:364)
at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:312)
at java.base/java.lang.reflect.Field.checkCanSetAccessible(Field.java:183)
at java.base/java.lang.reflect.Field.setAccessible(Field.java:177)
at demo.demo.main(demo.java:21)
Okay, let's get this thing up and running:
java --add-opens=java.base/java.io=ALL-UNNAMED demo.java
# On windows, it will print something like this
File: C:\Users\sa\AppData\Local\Temp\example-3357139619800720980.log, handle: 1176 (long)
# Other operating systems will be
File: /tmp/example-16018319640958431712.log, fd: 6 (int)
They are defined in the jdk source code like this:
public final class FileDescriptor {
private int fd;
private long handle;
//...
}
Source: FileDescriptor.java
Upvotes: 0
Reputation: 1415
This is only to be used in case of emergency (or until you find a different way since this is not supported) because it does things unintended by the API and is not supported. Caveat emptor.
package sandbox;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
public class GetFileHandle {
public static void main(String[] args) {
try (FileInputStream fis = new FileInputStream("somedata.txt")) {
FileDescriptor fd = fis.getFD();
Field field = fd.getClass().getDeclaredField("fd");
field.setAccessible(true);
Object fdId = field.get(fd);
field.setAccessible(false);
field = fd.getClass().getDeclaredField("handle");
field.setAccessible(true);
Object handle = field.get(fd);
field.setAccessible(false);
// One of these will be -1 (depends on OS)
// Windows uses handle, non-windows uses fd
System.out.println("fid.handle="+handle+" fid.fd"+fdId);
} catch (IOException | NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
Upvotes: 1