В Python как пользовательские файловые дескрипторы используются для ввода и вывода, включая настройку по умолчанию и окончательное закрытие?
Я хочу понять, как пользовательские файловые дескрипторы работают в Python для ввода, вывода, настройки по умолчанию и окончательного закрытия. У меня есть файл в Bash, который делает именно то, что я хочу сделать в Python. Может кто-нибудь сказать мне, как это будет сделано в Python? Я использую Python 2.7.5, Bash 4.2 и выполняю на CentOS 7.3.
настроить
$ echo "input string" > input
bash_fd.sh
#!/bin/bash
# Demonstration of custom file descriptors in Bash
# 3 script input (scrin)
# 4 script output (scrout)
# 5 script error (screrr)
# 6 script data (scrdata, demo: JSON return payload)
# 7 script log (scrlog)
fd_open()
{
### Provide defaults for file descriptors 3-7 ONLY if the FDs are undefined
{ >&3; } 2>/dev/null || exec 3<&0 # dup scrin to stdin
{ >&4; } 2>/dev/null || exec 4>&1 # dup scrout to stdout
{ >&5; } 2>/dev/null || exec 5>&2 # dup screrr to stderr
{ >&6; } 2>/dev/null || exec 6>/dev/null # set scrdata to /dev/null
{ >&7; } 2>/dev/null || exec 7>/dev/null # set scrlog to /dev/null
}
fd_close()
{
# Close all file descriptors
exec 3>&-
exec 4>&-
exec 5>&-
exec 6>&-
exec 7>&-
}
main()
{
fd_open # Ensure
echo "[$(date)] Program beginning" >&7 # scrlog
echo -n 'Enter a message: ' >&4 # scrout
read MSG <&3 # scrin
echo "Read message $MSG" >&4 # scrout
echo "[screrr] Read message $MSG" >&5 # screrr
echo "{\"msg\": \"$MSG\"}" >&6 # scrdata: return JSON payload
echo "[$(date)] Program finishing: $MSG" >&7 # scrlog
fd_close
return ${1:-0} # return status code
}
# For demonstration purposes, $1 is the return code returned when calling main
main "$1"
вызов
$ ./bash_fd.sh 37 3<input 4>scrout 5>screrr 6>scrdata 7>scrlog
$
код возврата
$ echo $?
37
сгенерированные файлы
$ cat scrout
Enter a message: Read message input string
$ cat screrr
[screrr] Read message input string
$ cat scrdata
{"msg": "input string"}
$ cat scrlog
[Wed Jun 14 21:33:24 EDT 2017] Program beginning
[Wed Jun 14 21:33:24 EDT 2017] Program finishing: input string
Любая помощь в переводе вышеупомянутого скрипта Bash на Python действительно поможет мне понять Python и пользовательские файловые дескрипторы и будет высоко оценена.
1 ответ
Файловый объект Python 2 является довольно тонкой оболочкой над C stdio
FILE
структура, которая сама содержит соответствующий дескриптор (целое число). Это не совпадение, что во многих местах документы ссылаются на stdio
вещи.
Каждый раз, когда вы создаете файл объекта (
open()
), дескриптор, соответствующий файлу, открывается и используется во всех операциях ввода-вывода с объектом.- Вы можете получить это с
<file>.fileno()
, - и наоборот, если у вас есть необработанный дескриптор, вы можете обернуть его файловым объектом с помощью
os.fdopen()
,- например, если вы приказали
bash
чтобы перенаправить определенные дескрипторы вашего скрипта, он открыл соответствующие дескрипторы для вашего подпроцесса.
- например, если вы приказали
- Вы можете получить это с
Когда файловый объект закрывается или собирается мусором, базовый дескриптор также закрывается.
- поскольку время сбора мусора неизвестно, начиная с версии 2.6 рекомендуется принудительно закрывать в конце блока с помощью
with open(...) as f:
чтобы файл не оставался открытым дольше, чем необходимо. - дескриптор закрывается, даже если объект файла был создан из необработанного дескриптора.
- поскольку время сбора мусора неизвестно, начиная с версии 2.6 рекомендуется принудительно закрывать в конце блока с помощью
os
Модуль имеет несколько других функций для работы с дескрипторами, которые отражают соответствующие функции C, такие какos.dup()
,
Как правило, вы должны использовать файловые объекты и не беспокоиться об их базовых дескрипторах. Вы можете сделать это даже с функциями, которые возвращают необработанные дескрипторы, как с os.pipe()
,
Примеры:
(объекты в угловых скобках - это псевдокод, показывающий, что нужно вставить туда)
Проверьте, существует ли дескриптор:
Как проверить, является ли данный файловый дескриптор, сохраненный в переменной, действительным? предлагает (только для UNIX) fcntl
или (переносной) dup
в качестве наименее навязчивых способов, так как вы собираетесь использовать его через файловый объект, лучше всего попытаться:
import os,errno
<...>
try: f = os.fdopen(<fd>)
except OSError as e:
if e.errno!=errno.EBADF: raise
else:
# actions when doesn't exist, maybe create `f' some other way
else:
#actions when exists
# use `f'
Дубликаты FDs
Не очень нужно - вы можете просто назначить, например, f = sys.stdin
в зависимости от состояния и использования f
, Единственный случай, когда вам действительно это нужно, это если вы должны предоставить дополнительные FD другим процессам.
new_fd = os.dup(fd)
использует наименьшее доступное число для нового FDos.dup2(old_fd,new_fd)
использует определенный, закрывая его, если он уже открыт
Например, чтобы дублировать FD файлового объекта и создать еще один файловый объект поверх дубликата:
os.dup2(old_f.fileno(),<new_fd>)
new_f = os.fdopen(<new_fd>)
Чтение из / Запись в / закрытие FD
Чтение из / запись в / закрытие / любой объект файла, обертывающий этот FD. См. Чтение и запись файлов - учебник по Python, единственное отличие состоит в том, что если у вас есть сырой FD, вы создаете объект файла с os.fdopen()
вместо open()
,