Использование нумерованного файлового дескриптора из 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.

Протестированное рабочее решение:

Ответ со специальными записями файловой системы дескриптора файла указал мне на следующее работоспособное решение:

  1. выясните, есть ли в вашей Unix-подобной системе специальная файловая система, содержащая именованные записи для всех файловых дескрипторов, и если да, то где.

    • I'm using FreeBSD where fdescfs(5) is a filesystem that does just this. Under Linux it would be procfs.
  2. убедитесь, что эта файловая система смонтирована

    • FreeBSD: поместите fdescfs /dev/fd fdescfs rw 0 0 в /etc/fstab

      или запустите mount -t fdescfs null /dev/fd в командной строке (возможно, с помощью sudo)

  3. Используйте новые FileInputStream("/dev/fd/3") и new FileOutputStream("/dev/fd/4") для подключения потоков к файловым дескрипторам (пути предназначены для FreeBSD, замените пути вашей операционной системы)


person Peer Stritzinger    schedule 30.01.2011    source источник
comment
kfu.com/~nsayer/Java/jni-filedesc.html может помочь   -  person    schedule 30.01.2011


Ответы (4)


Я почти уверен, что это невозможно сделать с помощью чистой Java — вам, вероятно, придется использовать собственный код для привязки дескриптора файла к объекту FileDescriptor или объекту FileInputStream или FileOutputStream.

ИЗМЕНИТЬ
Если вы используете Linux, *BSD или macOS, вы можете использовать псевдофайлы /dev/fd/nnn для доступа к файловому дескриптору nnn.

person Adrian Pronk    schedule 30.01.2011
comment
Да, узнав из ваших ответов, что это невозможно в самой Java (о чем я и не мечтал), я искал поддержку этой операционной системы. Я работаю под FreeBSD и имею /dev/fd/‹nnn› для всех дескрипторов открытых файлов. - person Peer Stritzinger; 30.01.2011

С помощью SUN JavaVM вы можете:

FileDescriptor fd = new FileDescriptor();
sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess().set(fd,3);
FileInputStream fin = new FileInputStream(fd);
person paf.goncalves    schedule 10.04.2012
comment
Это не поддерживается, а не API и не работает с Java 9. - person Philippe Marschall; 18.10.2017
comment
Тогда есть ли аналогичный подход для более новых версий Oracle HotSpot? А в OpenJDK? - person Corrodias; 11.03.2020

Недавно мне нужно было сделать это для дочернего процесса 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, который компилирует его, настраивает fd3 и запускает java-программу:

#!/bin/bash

javac TestFD.java

exec 3>&1  # open fd3, redirect to stdout
java TestFD
exec 3>&-

Разумеется, fd3 перенаправляется на стандартный вывод и выводит на терминал "привет\n". Закомментируйте строку «exec 3>&1», и программа Java завершится ошибкой, как и ожидалось, с IOException «Устройство не настроено».

Отражение конструктора private FileDescriptor, по-видимому, отлично работает в случаях, когда доступ к /dev/fd невозможен, и это менее неуклюже, чем попытка создать FileDescriptor с использованием JNI, предложение, которое я видел в другом месте.

Примечание. Я тестировал это в системе BSD. Это может или не может работать на других системах.

person shiblon    schedule 24.04.2016
comment
Это не работает в Windows, так как единственным конструктором является конструктор по умолчанию. - person FThompson; 03.01.2018

Начать с:

Приложения не должны создавать свои собственные файловые дескрипторы.

Вы можете попробовать использовать отражение для вызова конструктора private FileDescriptor(int fd), получив конструктор и вызвав для него setAccessible(true). Но это хак, и я не могу гарантировать, что он сработает (вероятнее всего, не сработает). Особенно учитывая цитату, с которой я начал.

person Bozho    schedule 30.01.2011
comment
Моя проблема в том, что эти файловые дескрипторы, которые я передаю, заданы временем выполнения другого языка и другими внешними ограничениями, на которые я не имею никакого влияния. Так что необходимость в этом не по моему выбору. Я попробую ваше предложение для взлома. - person Peer Stritzinger; 30.01.2011
comment
Как вы и подозревали... это не сработает. Я могу получить общедоступные конструкторы только через Class.getConstructor - person Peer Stritzinger; 30.01.2011
comment
@Peer Stritzinger - используйте FileDescriptor.getDeclaredConstructor(..) - person Bozho; 30.01.2011
comment
Совершенно правильно открывать необработанный дескриптор файла. Как еще родительский процесс может передать файл. - person ctrl-alt-delor; 05.07.2018