Quando os arquivos temporários Java são excluídos?

92

Suponha que eu crie um arquivo temporário em Java com o método

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

Se eu não chamar explicitamente o delete()método, quando o arquivo será excluído?

Como uma intuição, pode ser quando a JVM termina, ou antes (pelo Coletor de Lixo), ou mais tarde (por algum processo de varredura do Sistema Operacional).

Alphaaa
fonte
2
deleteOnExit ()
devnull
minhas desculpas, eu apenas verifiquei o método docs.oracle.com/javase/6/docs/api/java/io/… , que não fornece a resposta. A descrição longa está presente apenas no método com a assinatura mais longa.
Alphaaa de

Respostas:

95

O arquivo não será excluído automaticamente, no JavaDoc :

Este método fornece apenas parte de um recurso de arquivo temporário. Para fazer com que um arquivo criado por este método seja excluído automaticamente, use o método deleteOnExit ().

Portanto, você deve chamar explicitamente deleteOnExit () :

Solicita que o arquivo ou diretório indicado por este caminho abstrato seja excluído quando a máquina virtual for encerrada.

Kai
fonte
2
e se deleteOnExit for usado, ele será excluído "quando a máquina virtual for encerrada. Os arquivos (ou diretórios) são excluídos na ordem inversa em que estão registrados. Invocar este método para excluir um arquivo ou diretório que já está registrado para exclusão não tem efeito. A exclusão será tentada apenas para o encerramento normal da máquina virtual, conforme definido pela Especificação da linguagem Java. " portanto, ele não é excluído mesmo em todas as JVM existentes.
eis
obrigado, eu apenas verifiquei o método docs.oracle.com/javase/6/docs/api/java/io/… , que não fornece a resposta. A descrição longa está presente apenas no método com a assinatura mais longa
Alphaaa de
52

Como as outras respostas nota, arquivos temporários criados com File.createTempFile()o não ser excluído automaticamente, exceto que pedir explicitamente.

A maneira genérica e portátil de fazer isso é chamar .deleteOnExit()o Fileobjeto, o que agendará o arquivo para exclusão quando a JVM for encerrada. Uma ligeira desvantagem desse método, no entanto, é que ele só funciona se a VM terminar normalmente; em um encerramento anormal (ou seja, uma falha da VM ou encerramento forçado do processo VM), o arquivo pode permanecer não apagado.

Em sistemas Unixish (como Linux), é realmente possível obter uma solução um pouco mais confiável excluindo o arquivo temporário imediatamente após abri-lo . Isso funciona porque os sistemas de arquivos Unix permitem que um arquivo seja excluído ( desvinculado , para ser mais preciso) enquanto ele ainda está aberto por um ou mais processos. Esses arquivos podem ser acessados ​​normalmente por meio do filehandle aberto, e o espaço que ocupam no disco só será recuperado pelo sistema operacional após o último processo que mantém um identificador aberto para o arquivo sair.

Portanto, esta é a maneira mais confiável e portátil que conheço de garantir que um arquivo temporário seja excluído adequadamente após o encerramento do programa:

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();
        }
    }
}

Em um sistema Unixish, executar isso deve produzir algo como a seguinte saída:

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.

enquanto no Windows, a saída parece um pouco 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.

Em ambos os casos, entretanto, o arquivo temporário não deve permanecer no disco após o término do programa.


Ps. Ao testar esse código no Windows, observei um fato bastante surpreendente: aparentemente, apenas deixar o arquivo temporário aberto é suficiente para evitar que seja excluído . Obviamente, isso também significa que qualquer travamento que ocorrer enquanto o arquivo temporário estiver em uso fará com que ele não seja excluído, o que é exatamente o que estamos tentando evitar aqui.

AFAIK, a única maneira de evitar isso é garantir que o arquivo temporário sempre seja fechado usando um finallybloco. Obviamente, você também pode excluir o arquivo do mesmo finallybloco. Não tenho certeza do que usar, se é que alguma coisa, .deleteOnExit()realmente venceria você sobre isso.

Ilmari Karonen
fonte
1
Ótima resposta. Outra coisa importante a se notar deleteOnExit()é que se for chamado com frequência (digamos, em um sistema que usa muitos arquivos temporários novos), provavelmente causará um vazamento de memória (uma vez que tem que memorizar todos os caminhos que precisam ser excluído).
Eyal Roth
18

Se eu não chamar explicitamente o delete()método, quando o arquivo será excluído?

Não vai, pelo menos não por Java. Se você deseja que o arquivo seja excluído quando a JVM for encerrada, será necessário chamar tmp.deleteOnExit().

Ian Roberts
fonte
5

de: Como excluir arquivo temporário em Java

O arquivo temporário é usado para armazenar os dados menos importantes e temporários, que sempre devem ser excluídos quando o sistema for encerrado . A melhor prática é usar File.deleteOnExit () para fazer isso.

Por exemplo,

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

O exemplo acima criará um arquivo temporário denominado “abc.tmp” e o excluirá quando o programa for encerrado ou encerrado .

Se você deseja excluir o arquivo temporário manualmente , você ainda pode usar o File.delete ().

Grijesh Chauhan
fonte
Por que essa prática recomendada?
Frans
3

O arquivo temporário é usado para armazenar os dados menos importantes e temporários, que sempre devem ser excluídos quando o sistema for encerrado. A melhor prática é usar File.deleteOnExit () para fazer isso.

Por exemplo,

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

O exemplo acima criará um arquivo temporário denominado “abc.tmp” e o excluirá quando o programa for encerrado ou encerrado.

Juned Ahsan
fonte
-3

Você pode excluir manualmente o arquivo antes de encerrar o processo, se desejar; no entanto, quando o processo for encerrado, o arquivo também será excluído.

Jasper Ketelaar
fonte
3
Não, ele só será excluído na saída se você ligar especificamentedeleteOnExit()
Ian Roberts