从 /dev/input 读取几个字节时出现 IOException

IOException when reading few bytes from /dev/input

尝试从 /dev/input/event16 读取 input_events 时,我注意到我正在读取的缓冲区大小可能会导致异常。这是我写的代码:

    public static void main(String[] args) throws IOException{
        FileInputStream is = new FileInputStream("/dev/input/event16");
        byte[] three_bytes = new byte[3];
        byte[] twentyfour_bytes = new byte[24];
        is.read(three_bytes); // fails
        is.read(twentyfour_bytes); // does not fail

    }

我最初的实验表明缓冲区需要至少一个完整 input_event 结构的容量。但是我找不到原因。

问题是行 is.read(three_bytes); 导致以下异常:

Exception in thread "main" java.io.IOException: Invalid argument
        at java.base/java.io.FileInputStream.readBytes(Native Method)
        at java.base/java.io.FileInputStream.read(FileInputStream.java:249)
        at main.Test.main(Test.java:11)

我想弄清楚为什么 is.read(three_bytes); 行抛出异常而 is.read(twentyfour_bytes); 按预期读取数据

I would like to figure out why the line is.read(three_bytes); throws the exception while is.read(twentyfour_bytes); reads the data as expected.

首先,/dev/input/event16 不是常规文件。它是一个设备文件,而设备文件的行为通常不像普通文件。

在这种情况下,/dev/input/event* 设备文件用于从输入设备读取事件。当您对它们执行 read 系统调用时,它们将 return 一个或多个完整事件。这些是二进制数据,其格式由以下 C struct:

给出
struct input_event {    
    struct timeval time;    
    unsigned short type;
    unsigned short code;
    unsigned int value; 
};

不过,在典型的 64 位 Linux 系统上,该结构的大小(大概)是 24 字节。

My initial experiments suggest that the buffer needs capacity for at least one full input_event struct. But I could not find out why.

事件设备的行为记录在 Linux Input drivers v1.0 的第 5 节中。它指出 read 将始终给出整数个 input_event 结构。

因此,read 系统调用提供了一个小于 sizeof(input_event) 的缓冲区,内核不能 return 任何东西。显然,这会导致 read 系统调用失败,errno 值为 EINVAL。 (IMO,这是一个合理的设计选择,并且与EINVAL的文档含义一致。)


因此,在 Java 中,当您调用 read(three_bytes) 时,它将映射到读取大小为 3 字节的 read 系统调用,该调用失败;看上面。系统调用失败通过抛出 IOException.

向 Java 应用程序发出信号