6

Android 中的FileDescriptor API 说:

文件描述符类的实例用作表示打开文件、打开套接字或另一个字节源或接收器的底层机器特定结构的不透明句柄。

我想使用ByteArrayOutputStreamByteArrayInputStream创建一个 FileDescriptor 对象

此外,FileDescriptor 是最终类,不能被覆盖。它唯一的构造函数说 -

构造一个(无效的) FileDescriptor 对象。

知道如何在 Android 中使用 FileDescriptor 吗?

编辑

我想在MediaMuxer中使用它。我不想写入文件,而是希望将媒体数据保存在内存中并将其复制到 TCP 套接字以进行实时流式传输。所以我的 FileDescriptor 应该是一个“字节汇”。

4

2 回答 2

1

使用 a LocalSocket,但要小心,因为存在安全隐患。

LocalSocket是用于处理 Unix 域套接字的 Android API。域套接字类似于 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代表设备的文件。因为套接字是通过文件系统访问的,它受制于通常的文件系统权限,所以很容易通过将套接字放在应用程序的私有数据区来限制对套接字的访问。

由于这种技术会在文件系统上创建一个文件,因此最好在完成后删除该文件,并且可能每隔一段时间检查和清理旧套接字,以防您的应用程序崩溃并留下旧文件躺着。

于 2020-06-30T05:45:10.270 回答
-1

您可以将 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()));
于 2018-07-09T08:34:39.913 回答