os.read 关于 inotify 文件描述符:读取 32 个字节有效但 31 个字节引发异常
os.read on inotify file descriptor: reading 32 bytes works but 31 raises an exception
我正在编写一个应该使用 inotify 响应文件更改的程序。下面的框架程序按我的预期工作...
# test.py
import asyncio
import ctypes
import os
IN_CLOSE_WRITE = 0x00000008
async def main(loop):
libc = ctypes.cdll.LoadLibrary('libc.so.6')
fd = libc.inotify_init()
os.mkdir('directory-to-watch')
wd = libc.inotify_add_watch(fd, 'directory-to-watch'.encode('utf-8'), IN_CLOSE_WRITE)
loop.add_reader(fd, handle, fd)
with open(f'directory-to-watch/file', 'wb') as file:
pass
def handle(fd):
event_bytes = os.read(fd, 32)
print(event_bytes)
loop = asyncio.get_event_loop()
loop.run_until_complete(main(loop))
...因为它输出...
b'\x01\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00file\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
但是,如果我将其更改为尝试读取 31 个字节...
event_bytes = os.read(fd, 31)
...然后引发异常...
Traceback (most recent call last):
File "/usr/lib/python3.7/asyncio/events.py", line 88, in _run
self._context.run(self._callback, *self._args)
File "/t.py", line 19, in handle
event_bytes = os.read(fd, 31)
OSError: [Errno 22] Invalid argument
...同样适用于我尝试过的所有小于 31 的数字,包括 1 个字节。
这是为什么?我原以为它应该能够尝试读取任意数量的字节,并且只是 return 缓冲区中的任何内容,直到 os.read
.[=18= 的第二个参数给出的长度]
我是 运行 Alpine linux 3.10,在 Mac OS 上的 docker 容器中,具有非常基本的 Dockerfile:
FROM alpine:3.10
RUN apk add --no-cache python3
COPY test.py /
和运行它由
docker build . -t test && docker run -it --rm test python3 /test.py
这是因为它只允许读取 return 下一个事件的信息。来自 http://man7.org/linux/man-pages/man7/inotify.7.html
The behavior when the buffer given to read(2) is too small to return
information about the next event depends on the kernel version: in
kernels before 2.6.21, read(2) returns 0; since kernel 2.6.21,
read(2) fails with the error EINVAL.
#define EINVAL 22 /* Invalid argument */
大概映射到 Python OSError
和 Errno 22
。
我正在编写一个应该使用 inotify 响应文件更改的程序。下面的框架程序按我的预期工作...
# test.py
import asyncio
import ctypes
import os
IN_CLOSE_WRITE = 0x00000008
async def main(loop):
libc = ctypes.cdll.LoadLibrary('libc.so.6')
fd = libc.inotify_init()
os.mkdir('directory-to-watch')
wd = libc.inotify_add_watch(fd, 'directory-to-watch'.encode('utf-8'), IN_CLOSE_WRITE)
loop.add_reader(fd, handle, fd)
with open(f'directory-to-watch/file', 'wb') as file:
pass
def handle(fd):
event_bytes = os.read(fd, 32)
print(event_bytes)
loop = asyncio.get_event_loop()
loop.run_until_complete(main(loop))
...因为它输出...
b'\x01\x00\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00file\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'
但是,如果我将其更改为尝试读取 31 个字节...
event_bytes = os.read(fd, 31)
...然后引发异常...
Traceback (most recent call last):
File "/usr/lib/python3.7/asyncio/events.py", line 88, in _run
self._context.run(self._callback, *self._args)
File "/t.py", line 19, in handle
event_bytes = os.read(fd, 31)
OSError: [Errno 22] Invalid argument
...同样适用于我尝试过的所有小于 31 的数字,包括 1 个字节。
这是为什么?我原以为它应该能够尝试读取任意数量的字节,并且只是 return 缓冲区中的任何内容,直到 os.read
.[=18= 的第二个参数给出的长度]
我是 运行 Alpine linux 3.10,在 Mac OS 上的 docker 容器中,具有非常基本的 Dockerfile:
FROM alpine:3.10
RUN apk add --no-cache python3
COPY test.py /
和运行它由
docker build . -t test && docker run -it --rm test python3 /test.py
这是因为它只允许读取 return 下一个事件的信息。来自 http://man7.org/linux/man-pages/man7/inotify.7.html
The behavior when the buffer given to read(2) is too small to return information about the next event depends on the kernel version: in kernels before 2.6.21, read(2) returns 0; since kernel 2.6.21, read(2) fails with the error EINVAL.
#define EINVAL 22 /* Invalid argument */
大概映射到 Python OSError
和 Errno 22
。