Чтение файла с тайм-аутом в 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 поднимут это исключение)