Tengo un directorio que contiene archivos de datos servidos a los clientes, por ejemplo, /srv/data
. Al hacer una serie de actualizaciones, estoy trabajando en /srv/data_tmp
, y al final de la operación, me gustaría reemplazar atómicamente data
con data_tmp
. File.renameTo()
siempre devuelve falso para mí cuando el destino es un directorio existente. ¿Cómo puedo hacer esto?¿Cómo se puede reemplazar atómicamente un directorio por otro en Java?
Respuesta
Me temo que no puedes. No en el nivel SO al menos. Por lo tanto, incluso si administra la "atomicidad" en el contexto de su aplicación java, no tiene garantía de que algún otro proceso "fraudulento" interfiera en el nivel real del sistema de archivos.
Si yo fuera usted, leería this article (bastante viejo, pero debería darle algunas ideas) y luego veré si puede portar el enfoque sugerido a un more modern version.
¡Oh, espera, alguien ya hizo this!
Y al parecer usted no es the first one to ask here, ya sea
mejor de la suerte ...
Las transacciones de Apache Commons me permiten hacer esto de una manera muy ordenada, aunque solo en el contexto de mi aplicación Java. Lo cual es suficiente para mí ahora. ¡Gracias por tu enlace! –
Puede reemplazar el directorio /srv/data
con un enlace simbólico (o un junction in Windows XP) y cambiar el destino del enlace cuando corresponda. Sin embargo, no podrá hacer eso con una API de Java 6: tendrá que confiar en una biblioteca o escribir los comandos de línea de comando usted mismo.
NB: No garantizo nada sobre la atomicidad de esa operación.
El enfoque del enlace symbolik es interesante, pero está equivocado al decir que no puede cambiar el nombre de un archivo a un archivo que ya existe. Si tanto a como b existen en '/ home/me', esto sobrescribe con éxito b (a en Mac OS X/HFS +):' nuevo archivo ("/ home/me/a"). RenameTo (nuevo archivo ("/home/me/b ")' –
Oh, claro. No esperaba eso. –
La llamada al sistema Linux rename
no lo permite (la llamada al sistema rename
solo puede sobrescribir un directorio vacío), por lo que dudo que sea posible hacerlo en Java en Linux.
¿La llamada a 'rename' es atómica? Y si es así, también en el caso de sobrescribir? –
Sí, pero según la [página del manual ] (http://linux.die.net/man/2/rename) "cuando sobrescriba, probablemente haya una ventana en la que tanto oldpath como newpath se refieren al archivo que se renombra". –
lograr este objetivo es totalmente posible utilizar una combinación de "enlace simbólico" y "cambiar el nombre", junto con un intermedio tmp directorio. En el siguiente ejemplo se encuentra en la cáscara, pero se puede traducir fácilmente la funcionalidad aquí para utilizar las llamadas subyacentes:
mkdir -p tmp/real_dir1 tmp/real_dir2
touch tmp/real_dir1/a tmp/real_dir2/a
# start with ./target_dir pointing to tmp/real_dir1
ln -s tmp/real_dir1 target_dir
# create a symlink named target_dir in tmp, pointing to real_dir2
ln -sf tmp/real_dir2 tmp/target_dir
# atomically mv it into ./ replacing ./target_dir
mv tmp/target_dir ./
Ejemplo aquí tomados de: http://axialcorps.wordpress.com/2013/07/03/atomically-replacing-files-and-directories/
Esto se reduce a (en pseudo-código):
mkdir('./tmp');
mkdir('./tmp/real_dir1');
mkdir('./tmp/real_dir2');
symlink('./tmp/real_dir1', './target_dir')
symlink('./tmp/real_dir2', './tmp/target_dir')
rename('./tmp/target_dir', './target_dir')
El cambio de nombre final aquí es atómico, por lo que la acción tendrá éxito o fallará por completo, desde el punto de cualquier proceso que utiliza el directorio, la acción es atómica.
- 1. Mover un directorio atómicamente
- 2. ¿Se puede ejecutar esto atómicamente?
- 3. Posible crear AtomicReference que se puede intercambiar atómicamente?
- 4. java - escribir dos archivos atómicamente
- 5. ¿Cómo reemplazar un widget por otro usando Qt?
- 6. escribiendo atómicamente en un socket
- 7. ¿Se puede reemplazar una cadena por un diccionario?
- 8. "atómicamente" cambiar un System.Threading.Timer
- 9. No se puede reemplazar todo por el signo de dólar
- 10. Calculando todas las posibilidades de reemplazar un carácter por otro
- 11. writeToFile: atómicamente: ¿qué significa atómicamente?
- 12. ¿Cómo puedo eliminar archivos en un directorio que se copian de otro directorio?
- 13. En la ventanilla DropDownChoice ¿cómo se puede reemplazar "Elija uno" a otro texto
- 14. Cómo reemplazar "\" con "\\" en java
- 15. ¿Cómo combino un directorio en otro usando Bash?
- 16. ¿Cómo se puede extender un protocolo Clojure a otro protocolo?
- 17. ¿Se puede pasar un diccionario al reemplazar cadenas en Python?
- 18. ¿Se puede reemplazar la instrucción using por llaves?
- 19. reemplazar valores en un vector basado en otro vector
- 20. ¿Cómo puedo leer atómicamente un valor en ASM x86?
- 21. ¿Cómo comparar e incrementar atómicamente?
- 22. ¿Se puede agregar un directorio a la ruta de clase en tiempo de ejecución?
- 23. No se puede determinar el directorio actual
- 24. ¿Cómo puede un compañero encontrar otro compañero?
- 25. ¿Cómo escribo un script por lotes que copia un directorio a otro, reemplaza los archivos viejos?
- 26. ¿Es seguro reemplazar un objeto propio por otro objeto del mismo tipo en un método?
- 27. cómo reemplazar XmlGregorianCalendar por fecha?
- 28. reemplazar un archivo entero con otro archivo en bash
- 29. C# fusionar un directorio con otro
- 30. ¿Cómo cambio atómicamente 2 ints en C#?
Tiene alguna restricción en el sistema de archivos subyacente. Obviamente, si es FAT, no hay forma, ya que el sistema de archivos no lo admite. ¿Sabes si los dos directorios están en el mismo volumen físico? ¿Puedes usar las nuevas API JDK7 java.nio.file o tiene que funcionar en un JDK <= 6? –
No creo que las dos operaciones de traslado de archivos se puedan realizar "atómicamente", en el sentido estricto de la palabra. Algunos sistemas de archivos garantizan algunas [operaciones atómicas] (http://www.softpanorama.org/Internals/Filesystems/ntfs.shtml) pero no conozco ninguna forma de solicitar al sistema operativo que se lleven a cabo múltiples acciones del servicio atómico para todos procesos; ciertamente no en Java. – maerics
@Mike: Usaré HFS +, ext3 o NTFS, nunca FAT. Debería funcionar con JDK 6. –