¿Existe una forma estándar y confiable de crear un directorio temporal dentro de una aplicación Java? Hay una entrada en la base de datos de problemas de Java , que tiene un poco de código en los comentarios, pero me pregunto si hay una solución estándar en una de las bibliotecas habituales (Apache Commons, etc.).
364
temp.delete(); temp = new File(temp.getPath + ".d"); temp.mkdir(); ..., temp.delete();
.delete()
ymkdir()
: Un proceso malicioso podría crear el directorio de destino mientras tanto (tomando el nombre del archivo creado recientemente). VerFiles.createTempDir()
para una alternativa.La biblioteca Google Guava tiene muchas utilidades útiles. Una de las notas aquí es la clase de archivos . Tiene un montón de métodos útiles que incluyen:
Esto hace exactamente lo que pediste en una línea. Si lee la documentación aquí , verá que la adaptación propuesta
File.createTempFile("install", "dir")
generalmente introduce vulnerabilidades de seguridad.fuente
Si necesita un directorio temporal para la prueba y está utilizando jUnit,
@Rule
junto conTemporaryFolder
resuelve su problema:De la documentación :
Actualizar:
Si está utilizando JUnit Jupiter (versión 5.1.1 o superior), tiene la opción de utilizar JUnit Pioneer, que es el paquete de extensión JUnit 5.
Copiado de la documentación del proyecto :
Más información en JavaDoc y JavaDoc de TempDirectory
Gradle:
Maven
Actualización 2:
La anotación @TempDir se agregó a la versión JUnit Jupiter 5.4.0 como una característica experimental. Ejemplo copiado de la Guía del usuario de JUnit 5 :
fuente
El código escrito ingenuamente para resolver este problema adolece de condiciones de carrera, incluidas varias de las respuestas aquí. Históricamente, podría pensar detenidamente sobre las condiciones de carrera y escribirlo usted mismo, o podría usar una biblioteca de terceros como la guayaba de Google (como sugirió la respuesta de Spina). O podría escribir un código defectuoso.
Pero a partir de JDK 7, ¡hay buenas noticias! La biblioteca estándar de Java en sí misma ahora proporciona una solución que funciona correctamente (no rápida) a este problema. Desea java.nio.file.Files # createTempDirectory () . De la documentación :
Esto resuelve efectivamente el vergonzosamente antiguo informe de error en el rastreador de errores de Sun que pedía tal función.
fuente
Este es el código fuente de Files.createTempDir () de la biblioteca de Guava. No es tan complejo como podría pensar:
Por defecto:
Mira aquí
fuente
No lo use
deleteOnExit()
incluso si lo elimina explícitamente más tarde.Google 'deleteonexit es malo' para obtener más información, pero la esencia del problema es:
deleteOnExit()
solo se elimina en el caso de paradas normales de JVM, no se bloquea o mata el proceso de JVM.deleteOnExit()
solo se elimina al cerrar JVM; no es bueno para procesos de servidor de larga ejecución porque:El más malvado de todos:
deleteOnExit()
consume memoria para cada entrada de archivo temporal. Si su proceso se ejecuta durante meses o crea muchos archivos temporales en poco tiempo, consume memoria y nunca la libera hasta que se apaga la JVM.fuente
A partir de Java 1.7
createTempDirectory(prefix, attrs)
ycreateTempDirectory(dir, prefix, attrs)
están incluidos enjava.nio.file.Files
Ejemplo:
File tempDir = Files.createTempDirectory("foobar").toFile();
fuente
Esto es lo que decidí hacer para mi propio código:
fuente
Bueno, "createTempFile" realmente crea el archivo. Entonces, ¿por qué no simplemente eliminarlo primero y luego hacer el mkdir en él?
fuente
Este código debería funcionar razonablemente bien:
fuente
Como se discutió en este RFE y sus comentarios, puede llamar
tempDir.delete()
primero. O podría usarSystem.getProperty("java.io.tmpdir")
y crear un directorio allí. De cualquier manera, debe recordar llamartempDir.deleteOnExit()
, o el archivo no se eliminará una vez que haya terminado.fuente
Solo para completar, este es el código de la biblioteca google guava. No es mi código, pero creo que es valioso mostrarlo aquí en este hilo.
fuente
Tengo el mismo problema, así que esta es solo otra respuesta para aquellos que están interesados, y es similar a uno de los anteriores:
Y para mi aplicación, decidí agregar una opción para borrar la temperatura al salir, así que agregué en un gancho de apagado:
El método elimina todos los subdirectorios y archivos antes de eliminar la temperatura , sin usar la pila de llamadas (que es totalmente opcional y podría hacerlo con recursividad en este punto), pero quiero estar seguro.
fuente
Como puede ver en las otras respuestas, no ha surgido un enfoque estándar. Por lo tanto, ya mencionó Apache Commons, propongo el siguiente enfoque utilizando FileUtils de Apache Commons IO :
Esto se prefiere ya que apache commons es la biblioteca que se acerca más al "estándar" solicitado y funciona tanto con JDK 7 como con versiones anteriores. Esto también devuelve una instancia de archivo "antigua" (que está basada en transmisión) y no una instancia de ruta "nueva" (que está basada en búfer y sería el resultado del método getTemporaryDirectory () de JDK7) -> Por lo tanto, devuelve lo que la mayoría de la gente necesita cuando Quieren crear un directorio temporal.
fuente
Me gustan los múltiples intentos de crear un nombre único, pero incluso esta solución no descarta una condición de carrera. Se puede introducir otro proceso después de la prueba
exists()
y laif(newTempDir.mkdirs())
invocación del método. No tengo idea de cómo hacer que esto sea completamente seguro sin recurrir al código nativo, que supongo es lo que está enterrado dentroFile.createTempFile()
.fuente
Antes de Java 7 también podría:
fuente
Prueba este pequeño ejemplo:
Código:
Importaciones:
java.io.IOException
java.nio.file.Files
java.nio.file.Path
Salida de consola en máquina Windows:
C: \ Users \ userName \ AppData \ Local \ Temp \ tmpDir2908538301081367877
Comentario:
Files.createTempDirectory genera una ID única atómicamente: 2908538301081367877.
Nota:
lea lo siguiente para eliminar directorios de forma recursiva: elimine
directorios de forma recursiva en Java
fuente
Usar
File#createTempFile
ydelete
para crear un nombre único para el directorio parece estar bien. Debe agregar aShutdownHook
para eliminar el directorio (recursivamente) en el apagado de JVM.fuente