Создайте временный FIFO (named pipe) в Python?
Как создать временный FIFO (named pipe) в 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 и возможного удаления, поскольку он устарел.
EDIT. Примечательно, что я пробовал tempfile.NamedTemporaryFile
(и по расширению tempfile.mkstemp
), но os.mkfifo
throws:
OSError -17: Файл уже существует
когда вы запустите его в файлах, созданных mkstemp/NamedTemporaryFile.
Ответы
Ответ 1
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)
EDIT: я должен четко указать, что, поскольку уязвимость mktemp()
предотвращается этим, все еще существуют другие обычные проблемы безопасности, которые необходимо учитывать; например злоумышленник мог бы создать fifo (если бы у них были подходящие разрешения) до того, как ваша программа заработала, что может привести к сбою вашей программы, если ошибки/исключения неправильно обрабатываются.
Ответ 2
Как насчет использования
d = mkdtemp()
t = os.path.join(d, 'fifo')
Ответ 3
Если он используется в вашей программе, а не с любыми внешними, посмотрите на Queue module. В качестве дополнительного преимущества очереди python являются потокобезопасными.
Ответ 4
Возможно, вам будет удобно использовать следующий менеджер контекста, который создает и удаляет временный файл для вас:
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")
Ответ 5
Фактически, все, что 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")
Ответ 6
Почему бы просто не использовать 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)