Чтение файла с тайм-аутом в Python
В Linux есть файл, /sys/kernel/debug/tracing/trace_pipe
, который, как говорится в названии, является трубой. Итак, позвольте сказать, что я хочу прочитать первые 50 байтов от него с помощью Python - и я запускаю следующий код:
$sudo python -c 'f=open("/sys/kernel/debug/tracing/trace_pipe","r"); print f; print f.read(50); f.close()<br>
<open file '/sys/kernel/debug/tracing/trace_pipe', mode 'r' at 0xb7757e90>
Мы видим, что открытие файла происходит быстро (если у нас есть права суперпользователя), однако, если в этот trace_pipe
файл trace_pipe
пуст, он просто блокирует (и даже если есть контент, содержимое будет сбрасываться до тех пор, пока не будет не более, а затем снова будет заблокирован файл). Затем мне нужно нажать Ctrl - C, чтобы прервать скрипт Python с помощью KeyboardInterrupt
...
Как я могу заставить Python 2.7 читать с таймаутом?
То есть, я хочу проинструктировать Python "попробовать прочитать 50 байтов из этого файла, если вам не удастся через одну секунду отказаться и вернуться"?
Ответы
Ответ 1
использование
os.read(f.fileno(), 50)
вместо. Это не дожидается, пока указанное количество байтов не будет прочитано, но вернется, когда оно прочитает что-нибудь (не более указанного количества байтов).
Это не решит вашу проблему, если вам нечего читать с этого канала. В этом случае вы должны использовать select
из модуля select
чтобы проверить, есть ли что-то для чтения.
РЕДАКТИРОВАТЬ:
Тестирование пустого ввода с помощью select
:
import select
r, w, e = select.select([ f ], [], [], 0)
if f in r:
print os.read(f.fileno(), 50)
else:
print "nothing available!" # or just ignore that case
Ответ 2
f = os.open("/sys/kernel/debug/tracing/trace_pipe", os.O_RDONLY|os.O_NONBLOCK)
Следует предотвращать блокировку (работает только в Unix). Нет необходимости выбирать здесь..
Ответ 3
Просто добавив это как примечание, для лучшего форматирования:
@Alfe ответ в моем случае:
$ sudo python -c 'import os, select;
f=open("/sys/kernel/debug/tracing/trace_pipe","r"); print f;
rrdy, wrdy, xrdy = select.select([f], [], [], 1); print rrdy, wrdy, xrdy ;
timeout= "timed out" if (rrdy==[]) else "" ;
print timeout;
print os.read(f.fileno(), 50) if timeout=="" else "";
f.close() '
Если в файле есть что-то, я получаю ответ вроде:
<open file '/sys/kernel/debug/tracing/trace_pipe', mode 'r' at 0xb76f0e90>
[<open file '/sys/kernel/debug/tracing/trace_pipe', mode 'r' at 0xb76f0e90>] [] []
Xorg-1033 [001] 12570.075859: <user s
Если в файле ничего нет, я получаю:
<open file '/sys/kernel/debug/tracing/trace_pipe', mode 'r' at 0xb7831e90>
[] [] []
timed out
Обратите внимание, что документация select
не является явной, что параметр timeout
находится в секундах, но эти значения с плавающей запятой (например, 0,5) также работают.
@GabiMe ответ:
$ sudo python -c 'import os;
filno = os.open("/sys/kernel/debug/tracing/trace_pipe", os.O_RDONLY|os.O_NONBLOCK);
f=os.fdopen(filno, "r"); print f;
print "A", f.read(50);
print "B", os.read(f.fileno(), 50);
f.close() '
Если в файле есть что-то, я получаю ответ вроде:
<open file '<fdopen>', mode 'r' at 0xb77b6e90>
A bash-13777 [000] 13694.404519: sys_exi
B Timer-31065 [001] 13694.404830: sys_exi
Если в файле ничего нет, я получаю:
<open file '<fdopen>', mode 'r' at 0xb77c1e90>
A
Traceback (most recent call last):
File "<string>", line 1, in <module>
IOError: [Errno 11] Resource temporarily unavailable
... так что нужно запустить это в блоке try
, чтобы поймать IOError
, если в файле ничего нет... (и os.read
и f.read
поднимут это исключение)