2010-01-12 9 views
22

¿Cómo construyo una operación de escritura de archivo atómico? El archivo debe ser escrito por un servicio de Java y leído por scripts de Python.
Para el registro, las lecturas son mucho mayores que las escrituras. Pero la escritura ocurre en lotes y tiende a ser larga. El tamaño del archivo equivale a mega bytes.Operaciones de escritura de archivos atómicos (plataforma cruzada)

Ahora mismo mi enfoque es:

  • contenido del archivo de escritura a un archivo temporal en mismo directorio
  • eliminar el archivo de edad
  • Renombrar archivo temporal a nombre de archivo antiguo.

¿Es este el enfoque correcto? ¿Cómo se pueden evitar las condiciones en las que se elimina el archivo anterior, pero el nuevo nombre de archivo aún no se ha renombrado?

¿Estos lenguajes de programación (python y java) ofrecen construcciones para bloquear y evitar esta situación?

+2

Nota al margen: parece que Java NIO.2 tiene un mejor soporte para esto (al menos en el nivel de API): http://openjdk.java.net/projects/nio/javadoc/java/nio/file/Path .html # moveTo% 28java.nio.file.Path,% 20java.nio.file.CopyOption ...% 29 –

+0

Similar a http://stackoverflow.com/questions/1812115/how-to-safely-write-to -a-archivo –

+0

@Pascal. Está en Java 7. Largo camino por recorrer ... :-( –

Respuesta

8

AFAIK no.

Y la razón es que para que tal operación atómica sea posible, tiene que haber soporte de SO en la forma de un sistema de archivos transaccional. Y ninguno de los principales sistemas operativos ofrece un sistema de archivos transaccional.

EDIT - Estoy equivocado al menos para los sistemas POSIX. El sistema POSIX rename syscall realiza un reemplazo atómico si ya existe un archivo con el nombre de destino ... tal como lo señala @janneb. Eso debería ser suficiente para hacer la operación del OP de forma atómica.

Sin embargo, el hecho es que el método de Java es explícitamente File.renameTo() no garantiza que sea atómica, por lo que no proporciona una solución multiplataforma para el problema de la OP.

EDIT 2 - Con Java 7 puede usar java.nio.file.Files.move(Path source, Path target, CopyOption... options) con copyOptions y ATOMIC_MOVE. Si esto no es compatible (por el sistema de archivos/OS), debe obtener una excepción.

+1

+1: Ahhh, esas molestas diferencias de sistema operativo que impiden una solución de "plataforma cruzada" –

+0

Una respuesta real es que se deben usar bloqueos de archivos en su lugar. – unixman83

+0

"Y ninguno del sistema operativo principal ofrecen un sistema de archivos transaccional. "¿Qué? NTFS ha tenido soporte de transacciones durante mucho tiempo. http://msdn.microsoft.com/en-us/magazine/cc163388.aspx –

0
+1

Sí ... pero esto no le permitirá reemplazar un archivo atómico. –

+1

No tiene toda la razón. Con esta API puedes crear archivos ".lock" y usarlos como semáforo. Uso: si el archivo está bloqueado: Python espera hasta que se desbloquee, luego comienza a leer (y bloquea el archivo), después de leer el archivo de desbloqueo. Cuando el servicio necesita escribir datos, compruebe si el archivo está bloqueado, espere hasta que se desbloquee, bloquéelo, escriba datos, desbloquéelo. –

+0

De todos modos, esta es efectivamente una respuesta de solo enlace, y el enlace no explica cómo resolver la pregunta del OP. Para los estándares actuales, es una respuesta de baja calidad. –

1

Se podría tratar de usar un archivo adicional para actuar como una cerradura, pero no estoy seguro de si eso va a funcionar bien. (Le obligaría a crear una lógica de comprobación de bloqueo y reintento en ambos lados, java y python)

Otra solución podría ser no crear archivos, tal vez podría hacer que su proceso java escuche en un puerto y sirva datos desde allí en lugar de desde un archivo?

5

Al menos en plataformas POSIX, omita el paso 3 (borre el archivo anterior). En POSIX, se garantiza que el cambio de nombre dentro de un sistema de archivos sea atómico, y el cambio de nombre en la parte superior de un archivo existente lo reemplaza atómicamente.

1

Haga que las secuencias de comandos de Python soliciten permiso del servicio. Mientras el servicio está escribiendo, colocará un bloqueo en el archivo. Si el bloqueo existe, el servicio rechazará la solicitud de Python.

3

Es un problema clásico de productor/consumidor.Debería poder resolver esto usando el cambio de nombre de archivo, que es atómico en los sistemas POSIX.

2

En Linux, Solaris, Unix esto es fácil. Simplemente use rename() desde su programa o mv. Los archivos deben estar en el mismo sistema de archivos.

En Windows, esto es posible si puede controlar ambos programas. LockFileEx. Para lecturas, abra un shared lock en el archivo de bloqueo. Para las escrituras, abra un exclusive lock en el archivo de bloqueo. El bloqueo es extraño en Windows, por lo que recomiendo usar un archivo de bloqueo por separado para esto.

Cuestiones relacionadas