2010-03-30 12 views
10

Tengo un programa de Python que necesita crear un archivo temporal con nombre que se abrirá y cerrará un par de veces a lo largo del programa, y ​​se eliminará cuando el programa finalice. Por desgracia, ninguna de las opciones en tempfile parecen funcionar:¿Cómo creo un archivo temporal con nombre en Windows en Python?

  • TemporaryFile no tiene un nombre visible
  • NamedTemporaryFile crea un objeto de tipo fichero. Solo necesito un nombre de archivo. Intenté cerrar el objeto que devuelve (después de configurar delete = False) pero recibo errores de transmisión cuando intento abrir el archivo más tarde.
  • SpooledTemporaryFile no tiene un nombre visible
  • mkstemp devuelve el objeto de archivo abierto y el nombre; no garantiza el archivo se borra cuando el programa sale
  • mktemp devuelve el nombre del archivo, pero no garantiza el archivo se elimina cuando el programa sale

He intentado usar mktemp dentro un gestor de contexto, así:

def get_temp_file(suffix): 
    class TempFile(object): 
     def __init__(self): 
      self.name = tempfile.mktemp(suffix = '.test') 

     def __enter__(self): 
      return self 

     def __exit__(self, ex_type, ex_value, ex_tb): 
      if os.path.exists(self.name): 
       try: 
        os.remove(self.name) 
       except: 
        print sys.exc_info() 

    return TempFile() 

... pero eso me da un WindowsError(32, 'The process cannot access the file because it is being used by another process'). El nombre del archivo es utilizado por un proceso que genera mi programa, y ​​aunque me aseguro de que el proceso finalice antes de salir, parece que tengo una condición de carrera fuera de mi control.

¿Cuál es la mejor manera de lidiar con esto?

No es necesario preocuparse por la seguridad aquí; esto es parte de un módulo de prueba, por lo que la mayoría de las personas podrían hacer que nuestras pruebas de la unidad fracasen falsamente. ¡El horror!

+0

Los problemas de seguridad no afectan el programa utilizando el archivo temporal, que afectan a todo el sistema el archivo temporal se crea en (por ejemplo, enlaces simbólicos a un importante archivo después de haber sido creado). –

+0

¿Está seguro de que todos los objetos de archivo que abren el archivo temporal están cerrados correctamente? – user49117

+0

El nombre de archivo se pasa a un proceso de Windows a través de Popen(), y cuando he terminado con esto, invoco .flush() en las transmisiones .sysin, .sysout y .syserr y luego invoco .wait() en el proceso. Eso está envuelto en un ContextManager, así que estoy seguro de que se llama. No estoy seguro de qué más podría estar haciendo. –

Respuesta

1

Si no te importa la seguridad, ¿qué hay de malo en esto?

tmpfile_name = tempfile.mktemp() 
# do stuff 
os.unlink(tmpfile_name) 

Quizás esté intentando sobre-diseñar esto. Si desea asegurarse de que este archivo siempre se elimine cuando el programa finalice, puede ajustar su ejecución main() en un try/finally. ¡Mantenlo simple!

if __name__ == '__main__': 
    try: 
     tmpfile_name = tempfile.mktemp() 
     main() 
    except Whatever: 
     # handle uncaught exception from main() 
    finally: 
     # remove temp file before exiting 
     os.unlink(tmpfile_name) 
+2

os.unlink es lo mismo que os.remove, según la documentación. Si ese es el caso, debería obtener la misma excepción, ¿correcto? –

2

he tenido exactamente el mismo problema cuando tenía que guardar un archivo cargado en el archivo temporal abierto mediante el módulo csv. Lo más irritante fue que el nombre del archivo en WindowsError apuntaba al archivo temporal, pero al guardar el contenido del archivo cargado en el búfer StringIO y al insertar los datos del búfer en el archivo temporal, se solucionó el problema. Para mis necesidades eso fue suficiente ya que los archivos cargados siempre caben en la memoria.

El problema fue solo cuando cargué un archivo con un script a través del CGI de Apache, cuando ejecuté el script similar desde la consola no pude reproducir el problema.

4

Necesitaba algo similar hoy, y terminé escribiendo el mío. Estoy usando atexit.register() para registrar una devolución de llamada de función que elimina el archivo cuando el programa sale.

Tenga en cuenta que los estándares de codificación para esto son ligeramente diferentes de los estándares de codificación Python típicos (camelCase en lugar de using_underscores). Ajuste a voluntad, por supuesto.

def temporaryFilename(prefix=None, suffix='tmp', dir=None, text=False, removeOnExit=True): 
    """Returns a temporary filename that, like mkstemp(3), will be secure in 
    its creation. The file will be closed immediately after it's created, so 
    you are expected to open it afterwards to do what you wish. The file 
    will be removed on exit unless you pass removeOnExit=False. (You'd think 
    that amongst the myriad of methods in the tempfile module, there'd be 
    something like this, right? Nope.)""" 

    if prefix is None: 
     prefix = "%s_%d_" % (os.path.basename(sys.argv[0]), os.getpid()) 

    (fileHandle, path) = tempfile.mkstemp(prefix=prefix, suffix=suffix, dir=dir, text=text) 
    os.close(fileHandle) 

    def removeFile(path): 
     os.remove(path) 
     logging.debug('temporaryFilename: rm -f %s' % path) 

    if removeOnExit: 
     atexit.register(removeFile, path) 

    return path 
código de prueba

Super-básica:

path = temporaryFilename(suffix='.log') 
print path 
writeFileObject = open(path, 'w') 
print >> writeFileObject, 'yay!' 
writeFileObject.close() 

readFileObject = open(path, 'r') 
print readFileObject.readlines() 
readFileObject.close() 
Cuestiones relacionadas