Использование нумерованного файлового дескриптора из Java - PullRequest
17 голосов
/ 30 января 2011

Мне нужен доступ к пронумерованным дескрипторам файлов из 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.имеет специальную файловую систему, которая содержит именованные записи для всех файловых дескрипторов.

    • Я использую FreeBSD, где fdescfs (5) - файловая система, которая делает именно это.Под Linux это будет 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, замените пути к вашим операционным системам)

Ответы [ 4 ]

14 голосов
/ 30 января 2011

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

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

9 голосов
/ 10 апреля 2012

С помощью SUN JavaVM вы можете сделать:

FileDescriptor fd = new FileDescriptor();
sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess().set(fd,3);
FileInputStream fin = new FileInputStream(fd);
6 голосов
/ 25 апреля 2016

Мне недавно нужно было сделать это для дочернего процесса Java, работающего в тюрьме. Это означало, что у него не было доступа к файловой системе / dev / fd.

@ Божо прокомментировал, что отражение может или не может работать для создания объекта 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 перенаправляется на стандартный вывод и выводит "hi there \ n" на терминал. Закомментируйте строку "exec 3> & 1", и Java-программа завершится неудачно, как и ожидалось, с IOException "Устройство не настроено".

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

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

3 голосов
/ 30 января 2011

Для начала:

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

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

...