28 votos

¿Cuál es la mejor manera de abrir un archivo para acceso exclusivo en Python?

¿Cuál es la forma más elegante de resolver esto:

  • abrir un archivo para lectura, pero sólo si no está ya abierto para escritura
  • abrir un archivo para escritura, pero sólo si no está ya abierto para la lectura o la escritura

Las funciones integradas de trabajo como este

>>> path = r"c:\scr.txt"
>>> file1 = open(path, "w")
>>> print file1
<open file 'c:\scr.txt', mode 'w' at 0x019F88D8>
>>> file2 = open(path, "w")
>>> print file2
<open file 'c:\scr.txt', mode 'w' at 0x02332188>
>>> file1.write("111")
>>> file2.write("222")
>>> file1.close()

scr.txt ahora contiene '111'.

>>> file2.close()

scr.txt se ha sobrescrito, que ahora contiene '222' (en Windows, Python 2.4).

La solución debe trabajar dentro del mismo proceso (como en el ejemplo anterior), así como cuando otro proceso tiene abierto el archivo.
Es preferible, si un estrellarse el programa no se va a mantener las puertas abiertas.

15voto

Brian Puntos 48423

Creo que no es totalmente multiplataforma. En unix, el fcntl módulo se va a hacer esto para usted. Sin embargo en windows (que supongo que son por los caminos), usted necesitará utilizar el win32file módulo.

Afortunadamente, hay una aplicación portátil (portalocker) utilizando la plataforma método apropiado en el python libro de cocina.

Para usarlo, abra el archivo y, a continuación, llame al:

portalocker.lock(file, flags)

donde las banderas se portalocker.LOCK_EX para acceso de escritura exclusivo, o LOCK_SH compartidos, de acceso de lectura.

5voto

Federico A. Ramponi Puntos 23106

La solución debe trabajar dentro del mismo proceso (como en el ejemplo anterior), así como cuando otro proceso tiene abierto el archivo.

Si por 'otro proceso' que significa 'lo que el proceso' (es decir, no el programa), en Linux no hay manera de lograr esto, confiando sólo en las llamadas al sistema (fcntl & amigos). Lo que quiero es obligatorio bloqueo, y el Linux de manera a obtener es un poco más complicado:

Volver a montar la partición que contiene el archivo con la mand opción:

# mount -o remount,mand /dev/hdXY

Establecer el sgid bandera para su archivo:

# chmod g-x,g+s yourfile

En el código de Python, obtener un bloqueo exclusivo en ese archivo:

fcntl.flock(fd, fcntl.LOCK_EX)

Ahora incluso el gato no será capaz de leer el archivo hasta que se libere el bloqueo.

2voto

gz. Puntos 1979

Aquí empieza el win32 mitad de un portátil de la aplicación, que no necesita una separada del mecanismo de bloqueo.

Requiere que el de Python para Windows Extensiones para bajar a la api de win32, pero eso es casi obligatorio para python en windows ya, y como alternativa, se puede hacer con ctypes. El código podría ser adaptado para exponer más funcionalidad si es necesario (por ejemplo, permitiendo FILE_SHARE_READ , en lugar de no compartir en absoluto). Consulte también la documentación de MSDN para la CreateFile y WriteFile llamadas al sistema, y el artículo sobre cómo Crear y Abrir Archivos.

Como se ha mencionado, puede utilizar el estándar de fcntl módulo a implementar el unix de la mitad de este, si es necesario.

import winerror, pywintypes, win32file

class LockError(StandardError):
	pass

class WriteLockedFile(object):
	"""
	Using win32 api to achieve something similar to file(path, 'wb')
	Could be adapted to handle other modes as well.
	"""
	def __init__(self, path):
		try:
			self._handle = win32file.CreateFile(
				path,
				win32file.GENERIC_WRITE,
				0,
				None,
				win32file.OPEN_ALWAYS,
				win32file.FILE_ATTRIBUTE_NORMAL,
				None)
		except pywintypes.error, e:
			if e[0] == winerror.ERROR_SHARING_VIOLATION:
				raise LockError(e[2])
			raise
	def close(self):
		self._handle.close()
	def write(self, str):
		win32file.WriteFile(self._handle, str)

Así es como el ejemplo de arriba se comporta:

>>> path = "C:\\scr.txt"
>>> file1 = WriteLockedFile(path)
>>> file2 = WriteLockedFile(path) #doctest: +IGNORE_EXCEPTION_DETAIL
Traceback (most recent call last):
	...
LockError: ...
>>> file1.write("111")
>>> file1.close()
>>> print file(path).read()
111

1voto

kender Puntos 18446

Para hacer seguro a la hora de abrir archivos dentro de una aplicación, usted podría intentar algo como esto:

import time
class ExclusiveFile(file):
    openFiles = {}
    fileLocks = []

    class FileNotExclusiveException(Exception):
        pass

    def __init__(self, *args):

        sMode = 'r'
        sFileName = args[0]
        try:
            sMode = args[1]
        except:
            pass
        while sFileName in ExclusiveFile.fileLocks:
            time.sleep(1)

        ExclusiveFile.fileLocks.append(sFileName)

        if not sFileName in ExclusiveFile.openFiles.keys() or (ExclusiveFile.openFiles[sFileName] == 'r' and sMode == 'r'):
            ExclusiveFile.openFiles[sFileName] = sMode
            try:
                file.__init__(self, sFileName, sMode)
            finally:
                ExclusiveFile.fileLocks.remove(sFileName)
         else:
            ExclusiveFile.fileLocks.remove(sFileName)
            raise self.FileNotExclusiveException(sFileName)

    def close(self):
        del ExclusiveFile.openFiles[self.name]
        file.close(self)

De esa manera subclase file de la clase. Ahora acabo de hacer:

>>> f = ExclusiveFile('/tmp/a.txt', 'r')
>>> f
<open file '/tmp/a.txt', mode 'r' at 0xb7d7cc8c>
>>> f1 = ExclusiveFile('/tmp/a.txt', 'r')
>>> f1
<open file '/tmp/a.txt', mode 'r' at 0xb7d7c814>
>>> f2 = ExclusiveFile('/tmp/a.txt', 'w') # can't open it for writing now
exclfile.FileNotExclusiveException: /tmp/a.txt

Si abre primero con 'w' modo, no permitir que nunca más se abre, incluso en modo de lectura, tal como usted quería...

1voto

molasses Puntos 1150

Si usted tiene múltiples secuencias de comandos de Python acceso al mismo archivo hay un par de opciones:

Leer-solo método

  1. configurar el archivo como de sólo lectura cuando no está en uso
  2. antes de la lectura/escritura en el archivo de verificación si es de sólo lectura
  3. si no es de solo lectura, lo que significa que está en uso, y usted tendrá que esperar hasta que es leído-sólo una vez más
  4. si es de sólo lectura, a continuación, quite la marca de sólo-lectura, lectura/escritura en el archivo, a continuación, volver a aplicar el indicador de sólo lectura

Lockfile método

Mismo que el anterior, excepto que en lugar de utilizar el indicador de sólo lectura que crear un archivo llamado 'scr.txt.lock' cuando se quiere acceder al archivo y, a continuación, elimine el archivo cuando haya terminado.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by: