¿Cuándo se eliminan los archivos temporales de Java?

92

Supongamos que creo un archivo temporal en Java con el método

File tmp = File.createTempFile(prefix, suffix);

Si no llamo explícitamente al delete()método, ¿cuándo se eliminará el archivo?

Como una intuición, podría ser cuando la JVM termina, o antes (por el recolector de basura), o más tarde (por algún proceso de barrido del sistema operativo).

Alphaaa
fuente
2
deleteOnSalir ()
devnull
mis disculpas, solo verifiqué el método docs.oracle.com/javase/6/docs/api/java/io/… , que no proporciona la respuesta. La descripción larga solo está presente en el método con la firma más larga.
Alphaaa

Respuestas:

95

El archivo no se eliminará automáticamente de JavaDoc :

Este método proporciona solo una parte de una función de archivo temporal. Para hacer que un archivo creado por este método se elimine automáticamente, utilice el método deleteOnSalir ().

Entonces tienes que llamar explícitamente a deleteOnSalir () :

Solicita que el archivo o directorio indicado por este nombre de ruta abstracto se elimine cuando finalice la máquina virtual.

Kai
fuente
2
y si se usa deleteOnSalir, se eliminará "cuando la máquina virtual termine. Los archivos (o directorios) se eliminan en el orden inverso al que están registrados. Invocar este método para eliminar un archivo o directorio que ya está registrado para su eliminación no tiene efecto. La eliminación se intentará solo para la terminación normal de la máquina virtual, según lo define la Especificación del lenguaje Java ". por lo que no se elimina incluso en todas las JVM existentes.
EIS
gracias, solo revisé el método docs.oracle.com/javase/6/docs/api/java/io/… , que no proporciona la respuesta. La descripción larga solo está presente en el método con la firma más larga
Alphaaa
52

Como las otras respuestas en cuenta, los archivos temporales creados con File.createTempFile()se no se eliminarán de forma automática a menos que solicite explícitamente.

La forma genérica y portátil de hacer esto es llamar .deleteOnExit()al Fileobjeto, que programará el archivo para su eliminación cuando finalice la JVM. Sin embargo, una pequeña desventaja de este método es que solo funciona si la VM termina normalmente; en una terminación anormal (es decir, una falla de la máquina virtual o la terminación forzada del proceso de la máquina virtual), el archivo puede permanecer sin eliminar.

En sistemas Unixish (como Linux), es posible obtener una solución algo más confiable eliminando el archivo temporal inmediatamente después de abrirlo . Esto funciona porque los sistemas de archivos Unix permiten que un archivo sea eliminado ( desvinculado , para ser precisos) mientras aún está abierto por uno o más procesos. Se puede acceder a dichos archivos normalmente a través del identificador de archivo abierto, y el sistema operativo solo recuperará el espacio que ocupan en el disco después de que salga el último proceso que tiene un identificador abierto para el archivo.

Entonces, esta es la forma más confiable y portátil que conozco de asegurarme de que un archivo temporal se eliminará correctamente después de que el programa salga:

import java.io.File;
import java.io.RandomAccessFile;
import java.io.IOException;

public class TempFileTest
{
    public static void main(String[] args)
    {
        try {
            // create a temp file
            File temp = File.createTempFile("tempfiletest", ".tmp"); 
            String path = temp.getAbsolutePath();
            System.err.println("Temp file created: " + path);

            // open a handle to it
            RandomAccessFile fh = new RandomAccessFile (temp, "rw");
            System.err.println("Temp file opened for random access.");

            // try to delete the file immediately
            boolean deleted = false;
            try {
                deleted = temp.delete();
            } catch (SecurityException e) {
                // ignore
            }

            // else delete the file when the program ends
            if (deleted) {
                System.err.println("Temp file deleted.");
            } else {
                temp.deleteOnExit();
                System.err.println("Temp file scheduled for deletion.");
            }

            try {
                // test writing data to the file
                String str = "A quick brown fox jumps over the lazy dog.";
                fh.writeUTF(str);
                System.err.println("Wrote: " + str);

                // test reading the data back from the file
                fh.seek(0);
                String out = fh.readUTF();
                System.err.println("Read: " + out);

            } finally {
                // close the file
                fh.close();
                System.err.println("Temp file closed.");
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

En un sistema Unixish, ejecutar esto debería producir algo como el siguiente resultado:

Temp file created: /tmp/tempfiletest587200103465311579.tmp
Temp file opened for random access.
Temp file deleted.
Wrote: A quick brown fox jumps over the lazy dog.
Read: A quick brown fox jumps over the lazy dog.
Temp file closed.

mientras que en Windows, la salida se ve ligeramente diferente:

Temp file created: C:\DOCUME~1\User\LOCALS~1\Temp\tempfiletest5547070005699628548.tmp
Temp file opened for random access.
Temp file scheduled for deletion.
Wrote: A quick brown fox jumps over the lazy dog.
Read: A quick brown fox jumps over the lazy dog.
Temp file closed.

En cualquier caso, sin embargo, el archivo temporal no debe permanecer en el disco una vez finalizado el programa.


PD. Mientras probaba este código en Windows, observé un hecho bastante sorprendente: aparentemente, simplemente dejar el archivo temporal sin cerrar es suficiente para evitar que se elimine . Por supuesto, esto también significa que cualquier falla que ocurra mientras el archivo temporal está en uso hará que no se elimine, que es exactamente lo que estamos tratando de evitar aquí.

AFAIK, la única forma de evitar esto es asegurarse de que el archivo temporal siempre se cierre usando un finallybloque. Por supuesto, también podría eliminar el archivo en el mismo finallybloque. No estoy seguro de qué, en todo caso, el uso .deleteOnExit()realmente te beneficiaría con eso.

Ilmari Karonen
fuente
1
Gran respuesta. Otra cosa importante a tener en cuenta deleteOnExit()es que si se llama con frecuencia (digamos, en un sistema que usa muchos archivos temporales nuevos), probablemente causará una pérdida de memoria (ya que tiene que memorizar todas las rutas que deben ser eliminado).
Eyal Roth
18

Si no llamo explícitamente al delete()método, ¿cuándo se eliminará el archivo?

No lo hará, al menos no por Java. Si desea que el archivo se elimine cuando la JVM finalice, debe llamar tmp.deleteOnExit().

Ian Roberts
fuente
5

de: Cómo eliminar un archivo temporal en Java

El archivo temporal se utiliza para almacenar los datos temporales y menos importantes, que siempre deben eliminarse cuando se cierra el sistema . La mejor práctica es utilizar File.deleteOnSalir () para hacerlo.

Por ejemplo,

File temp = File.createTempFile("abc", ".tmp"); 
temp.deleteOnExit();

El ejemplo anterior creará un archivo temporal llamado “abc.tmp” y lo eliminará cuando el programa finalice o salga .

Si desea eliminar el archivo temporal manualmente , aún puede usar File.delete ().

Grijesh Chauhan
fuente
¿Por qué es esta la mejor práctica?
Frans
3

El archivo temporal se utiliza para almacenar los datos temporales y menos importantes, que siempre deben eliminarse cuando se cierra el sistema. La mejor práctica es utilizar File.deleteOnSalir () para hacerlo.

Por ejemplo,

File temp = File.createTempFile("abc", ".tmp"); 
temp.deleteOnExit();

El ejemplo anterior creará un archivo temporal llamado “abc.tmp” y lo eliminará cuando el programa finalice o salga.

Juned Ahsan
fuente
-3

Si lo desea, puede eliminar manualmente el archivo antes de finalizar el proceso; sin embargo, cuando finalice el proceso, el archivo también se eliminará.

Jasper Ketelaar
fuente
3
No, solo se eliminará al salir si llama específicamentedeleteOnExit()
Ian Roberts