Использование пронумерованного файлового дескриптора из Java
Мне нужно получить доступ к дескрипторам нумерованных файлов из Java - кроме 0, 1 или 2.
Как это можно сделать? Я просмотрел класс FileDescriptor
, но не нашел способа инициализировать его с заданным номером дескриптора файла.
В качестве конкретного примера можно предположить, что Java вызывается как дочерний процесс с другого языка программирования. Файловые дескрипторы 3 и 4 предоставляются другим языком для ввода и вывода.
В Java мне нужны объекты InputStream
и OutputStream
, связанные с этими файловыми дескрипторами, так же как System.in, System.out и System.error связаны с файловыми дескрипторами 0, 1 и 2.
Я использую Java 1.6, и это должно работать на Unix-подобных системах.
Протестированное рабочее решение:
Ответ на записи файловой дескрипторной специальной файловой системы показал мне следующее работоспособное решение:
-
узнать, если и где ваша система Unix имеет специальную файловую систему, содержащую именованные записи для всех дескрипторов файлов.
- Я использую FreeBSD, где fdescfs (5) - это файловая система, которая делает именно это. В Linux это будет procfs.
-
убедитесь, что эта файловая система установлена
-
FreeBSD: поместите fdescfs /dev/fd fdescfs rw 0 0
в /etc/fstab
или запустите mount -t fdescfs null /dev/fd
в командной строке (возможно, с помощью sudo)
-
Используйте новые FileInputStream("/dev/fd/3")
и new FileOutputStream("/dev/fd/4")
, чтобы получить потоки, подключенные к файловым дескрипторам (пути для FreeBSD, заменить на пути к вашей операционной системе)
Ответы
Ответ 1
Я уверен, что это невозможно сделать с использованием чистой Java - вам, вероятно, придется использовать собственный код для привязки дескриптора файла к объекту FileDescriptor или к объекту FileInputStream или FileOutputStream.
ИЗМЕНИТЬ
Если вы используете Linux, * BSD или macOS, вы можете использовать псевдо файлы /dev/fd/nnn для доступа к файловому дескриптору nnn.
Ответ 2
С помощью SUN JavaVM вы можете:
FileDescriptor fd = new FileDesciptor();
sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess().set(fd,3);
FileInputStream fin = new FileInputStream(fd);
Ответ 3
Мне недавно нужно было сделать это для дочернего процесса Java, работающего в тюрьме. Это означало, что у него не было доступа к файловой системе /dev/fd.
@Bozho сделал комментарий, что отражение может или не может работать для создания объекта 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<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());
}
}
Чтобы проверить это, я сделал простой Bash script, который его компилирует, устанавливает fd3 и запускает программу java:
#!/bin/bash
javac TestFD.java
exec 3>&1 # open fd3, redirect to stdout
java TestFD
exec 3>&-
Конечно, fd3 перенаправляется на stdout и выводит "hi there there\n" на терминал. Прокомментируйте строку "exec 3 > & 1", и программа Java завершится неудачно, как ожидалось, с "Не настроенным устройством" IOException.
Отражение в частном конструкторе FileDescriptor, похоже, отлично работает в тех случаях, когда доступ к /dev/fd невозможен и менее неуклюж, чем попытка создания FileDescriptor с использованием JNI, предложение, которое я видел в другом месте.
Примечание. Я тестировал это в системе BSD. Он может работать или не работать в других системах.
Ответ 4
Для начала:
Приложения не должны создавать свои собственные файловые дескрипторы
Вы можете попробовать использовать отражение, чтобы вызвать конструктор private FileDescriptor(int fd)
, получив конструктор и набрав setAccessible(true)
на нем. Но это взломать, и я не могу гарантировать, что это сработает (скорее всего, этого не произойдет). Особенно учитывая цитату, которую я начал с.