python - namedtemporaryfile - ¿Cómo crear un archivo temporal que pueda leer un subproceso?
tempfile ruby (4)
Al menos, si abre un archivo temporal utilizando las bibliotecas de Python existentes, acceder a él desde múltiples procesos no es posible en el caso de Windows. Según MSDN , puede especificar un indicador de modo compartido del tercer parámetro ( dwSharedMode
) FILE_SHARE_READ
para CreateFile()
función CreateFile()
que:
Permite las operaciones abiertas posteriores en un archivo o dispositivo para solicitar acceso de lectura. De lo contrario, otros procesos no pueden abrir el archivo o el dispositivo si solicitan acceso de lectura. Si no se especifica este indicador, pero el archivo o dispositivo se ha abierto para el acceso de lectura, la función falla.
Por lo tanto, puede escribir una rutina de C específica de Windows para crear una función de apertura de archivo temporal personalizada, llamarla desde Python y luego puede hacer que su subproceso acceda al archivo sin ningún error. Pero creo que debes seguir con tu enfoque actual, ya que es la versión más portátil y funcionará en cualquier sistema y, por lo tanto, es la implementación más elegante.
- La discusión sobre Linux y el bloqueo de archivos de Windows se puede encontrar here .
EDITAR: Resulta que también es posible abrir y leer el archivo temporal de múltiples procesos en Windows. Ver la answer Piotr Dobrogost.
Estoy escribiendo un script de Python que necesita escribir algunos datos en un archivo temporal, luego crea un subproceso que ejecuta un programa C ++ que leerá el archivo temporal. Estoy intentando usar NamedTemporaryFile
para esto, pero de acuerdo con los documentos,
Si el nombre se puede utilizar para abrir el archivo una segunda vez, mientras que el archivo temporal nombrado sigue abierto, varía en todas las plataformas (se puede usar así en Unix, no puede en Windows NT o posterior).
Y, de hecho, en Windows si limpio el archivo temporal después de escribir, pero no lo cierro hasta que quiera que desaparezca, el subproceso no puede abrirlo para leerlo.
Estoy trabajando en esto creando el archivo con delete=False
, cerrándolo antes de generar el subproceso, y luego eliminándolo manualmente una vez que haya terminado:
fileTemp = tempfile.NamedTemporaryFile(delete = False)
try:
fileTemp.write(someStuff)
fileTemp.close()
# ...run the subprocess and wait for it to complete...
finally:
os.remove(fileTemp.name)
Esto parece poco elegante. ¿Hay una mejor manera de hacer esto? ¿Quizás una forma de abrir los permisos en el archivo temporal para que el subproceso pueda acceder a él?
Dado que nadie más parece estar interesado en dejar esta información a la intemperie ...
tempfile
expone una función, mkdtemp()
, que puede trivializar este problema:
try:
temp_dir = mkdtemp()
temp_file = make_a_file_in_a_dir(temp_dir)
do_your_subprocess_stuff(temp_file)
remove_your_temp_file(temp_file)
finally:
os.rmdir(temp_dir)
Dejo la implementación de las funciones intermedias en mkstemp()
del lector, ya que uno podría desear hacer cosas como usar mkstemp()
para reforzar la seguridad del archivo temporal en sí mismo, o sobrescribir el archivo en el lugar antes de eliminarlo. No sé particularmente qué restricciones de seguridad uno podría tener que no se planean fácilmente al consultar el origen del tempfile
.
De todos modos, sí, usar NamedTemporaryFile
en Windows puede ser poco elegante, y mi solución aquí también puede ser poco elegante, pero ya has decidido que el soporte de Windows es más importante que el código elegante, así que puedes seguir adelante y hacer algo legible.
Siempre puede ir a bajo nivel, aunque no estoy seguro si es lo suficientemente limpio para usted:
fd, filename = tempfile.mkstemp()
try:
os.write(fd, someStuff)
os.close(fd)
# ...run the subprocess and wait for it to complete...
finally:
os.remove(filename)
bugs.python.org/issue14243#msg164504 con Richard Oudkerk
(...) la única razón por la que falla la
NamedTemporaryFile
en Windows es porque cuando volvemos a abrir necesitamos usarO_TEMPORARY
.
y él da un ejemplo de cómo hacer esto en Python 3.3+
import os, tempfile
DATA = b"hello bob"
def temp_opener(name, flag, mode=0o777):
return os.open(name, flag | os.O_TEMPORARY, mode)
with tempfile.NamedTemporaryFile() as f:
f.write(DATA)
f.flush()
with open(f.name, "rb", opener=temp_opener) as f:
assert f.read() == DATA
assert not os.path.exists(f.name)
Debido a que no hay un parámetro de opener
en el built-in open()
en Python 2.x, tenemos que combinar las funciones de menor nivel os.open()
y os.fdopen()
para lograr el mismo efecto:
import subprocess
import tempfile
DATA = b"hello bob"
with tempfile.NamedTemporaryFile() as f:
f.write(DATA)
f.flush()
subprocess_code = /
"""import os
f = os.fdopen(os.open(r''{FILENAME}'', os.O_RDWR | os.O_BINARY | os.O_TEMPORARY), ''rb'')
assert f.read() == b''{DATA}''
""".replace(''/n'', '';'').format(FILENAME=f.name, DATA=DATA)
subprocess.check_output([''python'', ''-c'', subprocess_code]) == DATA