Создать временный FIFO (именованный канал) в Python?
Как вы можете создать временный FIFO (именованный канал) в Python? Это должно работать:
import tempfile
temp_file_name = mktemp()
os.mkfifo(temp_file_name)
open(temp_file_name, os.O_WRONLY)
# ... some process, somewhere, will read it ...
Однако я колеблюсь из-за большого предупреждения в Python Docs 11.6 и потенциального удаления, потому что оно устарело.
РЕДАКТИРОВАТЬ: Примечательно, что я пытался tempfile.NamedTemporaryFile
(и, соответственно, tempfile.mkstemp
), но os.mkfifo
броски:
OSError -17: файл уже существует
когда вы запускаете его для файлов, созданных mkstemp/NamedTevenFile.
6 ответов
os.mkfifo()
потерпит неудачу за исключением OSError: [Errno 17] File exists
если файл уже существует, то здесь нет проблем с безопасностью. Проблема безопасности с использованием tempfile.mktemp()
является условием гонки, при котором злоумышленник может создать файл с таким же именем, прежде чем открыть его самостоятельно, но так как os.mkfifo()
не удается, если файл уже существует, это не проблема.
Тем не менее, так как mktemp()
не рекомендуется использовать его. Ты можешь использовать tempfile.mkdtemp()
вместо:
import os, tempfile
tmpdir = tempfile.mkdtemp()
filename = os.path.join(tmpdir, 'myfifo')
print filename
try:
os.mkfifo(filename)
except OSError, e:
print "Failed to create FIFO: %s" % e
else:
fifo = open(filename, 'w')
# write stuff to fifo
print >> fifo, "hello"
fifo.close()
os.remove(filename)
os.rmdir(tmpdir)
РЕДАКТИРОВАТЬ: Я должен дать понять, что только потому, что mktemp()
Это устраняет уязвимость, но есть и другие обычные проблемы безопасности, которые необходимо учитывать; например, злоумышленник может создать fifo (если у него есть подходящие разрешения) до того, как это сделала ваша программа, что может привести к ее аварийному завершению, если ошибки / исключения не обрабатываются должным образом.
Возможно, вам будет удобно использовать следующий менеджер контекста, который создает и удаляет временный файл для вас:
import os
import tempfile
from contextlib import contextmanager
@contextmanager
def temp_fifo():
"""Context Manager for creating named pipes with temporary names."""
tmpdir = tempfile.mkdtemp()
filename = os.path.join(tmpdir, 'fifo') # Temporary filename
os.mkfifo(filename) # Create FIFO
yield filename
os.unlink(filename) # Remove file
os.rmdir(tmpdir) # Remove directory
Вы можете использовать это, например, так:
with temp_fifo() as fifo_file:
# Pass the fifo_file filename e.g. to some other process to read from.
# Write something to the pipe
with open(fifo_file, 'w') as f:
f.write("Hello\n")
Как насчет использования
d = mkdtemp()
t = os.path.join(d, 'fifo')
Если это для использования в вашей программе, а не с какими-либо внешними, взгляните на модуль очереди. Как дополнительное преимущество, очереди Python являются потокобезопасными.
Фактически, все это mkstemp
делает это работает mktemp
в цикле и продолжает пытаться создать исключительно, пока это не удастся (см. исходный код stdlib здесь). Вы можете сделать то же самое с os.mkfifo
:
import os, errno, tempfile
def mkftemp(*args, **kwargs):
for attempt in xrange(1024):
tpath = tempfile.mktemp(*args, **kwargs)
try:
os.mkfifo(tpath, 0600)
except OSError as e:
if e.errno == errno.EEXIST:
# lets try again
continue
else:
raise
else:
# NOTE: we only return the path because opening with
# os.open here would block indefinitely since there
# isn't anyone on the other end of the fifo.
return tpath
else:
raise IOError(errno.EEXIST, "No usable temporary file name found")
Почему бы просто не использовать mkstemp ()?
Например:
import tempfile
import os
handle, filename = tempfile.mkstemp()
os.mkfifo(filename)
writer = open(filename, os.O_WRONLY)
reader = open(filename, os.O_RDONLY)
os.close(handle)