Создайте дескриптор файла в памяти

API FileDescriptor в Android говорит:

Экземпляры класса дескриптора файла служат непрозрачным дескриптором базовой машинно-зависимой структуры, представляющей открытый файл, открытый сокет или другой источник или приемник байтов.

Я хочу создать объект FileDescriptor, используя ByteArrayOutputStream и ByteArrayInputStream

Кроме того, FileDescriptor является последним классом и не может быть переопределен. Единственный конструктор в нем говорит:

Создает (недопустимый) объект FileDescriptor.

Есть идеи, как использовать FileDescriptor в Android?

ИЗМЕНИТЬ

Я хочу использовать его в MediaMuxer. Вместо записи в файл я хочу иметь мультимедийные данные в памяти и копировать их в сокет TCP для потоковой передачи в реальном времени. Так что мой FileDescriptor должен быть «стоком байтов».


comment
откуда вы хотите вернуть этот FileDescriptor? из ContentProvider?   -  person pskink    schedule 24.10.2017
comment
Используйте ParcelFileDescriptor.createPipe() и kin, хотя я не уверен, что он будет делать то, что вы хотите.   -  person CommonsWare    schedule 24.10.2017
comment
Я хочу использовать его в MediaMuxer (FileDescriptor fd, int format), чтобы я мог записывать байты в выходной поток сокета TCP без записи данных в файл.   -  person PC.    schedule 24.10.2017
comment
затем используйте метод ParcelFileDescriptor#fromSocket()   -  person pskink    schedule 24.10.2017
comment
#fromSocket () у меня не сработал. E/MPEG4Writer: cannot seek mFd: Illegal seek (29) 47 Невозможно найти выходной поток сокета TCP. Итак, ищем другое решение, которое включает ByteArrayOutputStream с FileDescriptor.   -  person PC.    schedule 24.10.2017
comment
так что попробуйте то, что сказал @CommonsWare: создайте канал, но я думаю, вы получите ту же ошибку "cannot seek mFd" - я считаю, что доступен только физический файл   -  person pskink    schedule 24.10.2017
comment
@ПК. Вы нашли решение?   -  person mh taqia    schedule 14.06.2018
comment
@mh taquia Нет. Я этого не делал.   -  person PC.    schedule 14.06.2018
comment
@ПК. Как вы ее решили?   -  person Abu Noman    schedule 25.06.2020


Ответы (2)


Используйте LocalSocket, но будьте осторожны, поскольку это может сказаться на безопасности.

LocalSocket - это Android API для работы с сокетами домена Unix. Доменные сокеты похожи на сокеты TCP / IP, за исключением того, что они существуют только на устройстве, их нельзя использовать для связи по сети.

Вот простое, но небезопасное решение вашей проблемы:

// Create a unique name for the socket.
String name = "your.package.name-" + UUID.randomUUID();

// Bind a server to the socket.
final LocalServerSocket server = new LocalServerSocket(name);

// Connect a client to the socket.
LocalSocket client = new LocalSocket(LocalSocket.SOCKET_STREAM);
client.connect(new LocalSocketAddress(name, LocalSocketAddress.Namespace.ABSTRACT));

// Start a thread to read from the server socket.
new Thread(new Runnable {
    @Override
    public void run() {
        LocalSocket socket = server.accept();

        // To read data sent by the client, read from socket.getInputStream().
        // To send data to the client, write to socket.getOutputStream().

        // After you are done you will need to call socket.close().
    }
}).start();

// Get the FileDescriptor associated with the client.
// You can use this FileDescriptor to write data to and/or read data
// sent from the server.
FileDescriptor fileDescriptor = client.getFileDescriptor();

// After you are done you will need to call server.close() and client.close().

Это создает сокет в абстрактном пространстве имен сокетов. Это небезопасно, потому что сокеты домена являются общесистемными, а сокеты в абстрактном пространстве имен не ограничены какой-либо системой разрешений. Единственное требование для подключения или привязки к имени в абстрактном пространстве имен - это знать имя, а имя сокета, используемое вашим приложением, может быть легко обнаружено злоумышленником посредством декомпиляции. Также существует вероятность того, что другое приложение может случайно использовать то же имя сокета. Таким образом, другое приложение может перехватить ваши данные или отправить неожиданные данные через сокет, и от этого трудно защититься.

Лучшее, но более сложное решение - создать сокет в пространстве имен файловой системы. API для этого очень странный, но этого можно добиться следующим образом:

// Create a unique name for the socket in your app's private data area.
// Note this example creates a file named like socket-xxxx in the root of
// your app's private data area. You might want to put it in a subdirectory.
String name = context
    .getFileStreamPath("socket-" + UUID.randomUUID())
    .getAbsolutePath();
LocalSocketAddress address = new LocalSocketAddress(name, LocalSocketAddress.Namespace.FILESYSTEM);

// Bind a server to the socket.
LocalSocket server = new LocalSocket(LocalSocket.SOCKET_STREAM);
server.bind(address);
final LocalServerSocket serverWrapper = new LocalServerSocket(server.getFileDescriptor());

// Connect a client to the socket.
LocalSocket client = new LocalSocket(LocalSocket.SOCKET_STREAM);
client.connect(address);

// Start a thread to read from the server socket.
new Thread(new Runnable {
    @Override
    public void run() {
        LocalSocket socket = serverWrapper.accept();

        // To read data sent by the client, read from socket.getInputStream().
        // To send data to the client, write to socket.getOutputStream().

        // After you are done you will need to call socket.close() and
        // serverWrapper.close().
    }
}).start();

// Get the FileDescriptor associated with the client.
// You can use this FileDescriptor to write data to and/or read data
// sent from the server.
FileDescriptor fileDescriptor = client.getFileDescriptor();

// After you are done you will need to call server.close() and client.close().

Это создает файл в файловой системе, но никакие данные, проходящие через сокет, никогда не записываются на диск, они полностью находятся в памяти. Файл - это просто имя, представляющее сокет, аналогично файлам в /dev, которые представляют устройства. Поскольку доступ к сокету осуществляется через файловую систему, на него распространяются обычные разрешения файловой системы, поэтому легко ограничить доступ к сокету, поместив сокет в область личных данных вашего приложения.

Поскольку этот метод создает файл в файловой системе, было бы неплохо удалить файл после того, как вы закончите, а также, возможно, время от времени проверять и очищать старые сокеты, на случай, если ваше приложение выйдет из строя и оставит старые файлы. валяется.

person Daniel Cassidy    schedule 30.06.2020

Вы можете перенаправить System.out в ByteArrayOutputStream и использовать FileDescriptor.out в качестве дескриптора файла

ByteArrayOutputStream buff = new ByteArrayOutputStream();
PrintStream old = System.out;
System.setOut(new PrintStream(buff));

... use FileDescriptor.out ...

System.setOut(old);
System.out.println(new String(buff.toByteArray()));
person user3333515    schedule 09.07.2018