Kiedy pliki tymczasowe Java są usuwane?

92

Załóżmy, że utworzę plik tymczasowy w Javie za pomocą metody

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

Jeśli nie wywołam tej delete()metody bezpośrednio, kiedy plik zostanie usunięty?

Zgodnie z intuicją może to nastąpić, gdy JVM zakończy działanie, lub wcześniej (przez moduł wyrzucania elementów bezużytecznych) lub później (przez jakiś proces czyszczenia systemu operacyjnego).

Alphaaa
źródło
2
deleteOnExit ()
devnull
przepraszam, sprawdziłem tylko metodę docs.oracle.com/javase/6/docs/api/java/io/… , która nie daje odpowiedzi. Długi opis występuje tylko w metodzie z dłuższym podpisem.
Alphaaa

Odpowiedzi:

95

Plik nie zostanie automatycznie usunięty z JavaDoc :

Ta metoda zapewnia tylko część narzędzia do plików tymczasowych. Aby ustawić automatyczne usuwanie pliku utworzonego tą metodą, użyj metody deleteOnExit ().

Więc musisz jawnie wywołać deleteOnExit () :

Żąda usunięcia pliku lub katalogu oznaczonego tą abstrakcyjną nazwą ścieżki po zakończeniu działania maszyny wirtualnej.

Kai
źródło
2
a jeśli jest używane deleteOnExit, zostanie ono usunięte "po zakończeniu działania maszyny wirtualnej. Pliki (lub katalogi) są usuwane w odwrotnej kolejności, w jakiej zostały zarejestrowane. Wywołanie tej metody w celu usunięcia pliku lub katalogu, który jest już zarejestrowany do usunięcia, nie ma Efekt. Próba usunięcia nastąpi tylko w przypadku normalnego zakończenia maszyny wirtualnej, zgodnie z definicją w specyfikacji języka Java. " więc nie jest usuwany nawet na wszystkich istniejących maszynach JVM.
eis
dzięki, sprawdziłem tylko metodę docs.oracle.com/javase/6/docs/api/java/io/… , która nie daje odpowiedzi. Długi opis występuje tylko w metodzie z dłuższym podpisem
Alphaaa
52

Jak zauważają inni odpowiedzi, pliki tymczasowe utworzone za pomocą nieFile.createTempFile() będą zostać automatycznie usunięte, chyba że wyraźnie o to poproszą.

Rodzajową, przenośny sposób to zrobić, to zadzwonić .deleteOnExit()naFile obiekcie, który zaplanuje plik do usunięcia, gdy JVM kończy. Niewielką wadą tej metody jest jednak to, że działa ona tylko wtedy, gdy maszyna wirtualna kończy normalnie; w przypadku nieprawidłowego zakończenia (tj. awarii maszyny wirtualnej lub wymuszonego zakończenia procesu maszyny wirtualnej) plik może pozostać nieusunięty.

W systemach Unixish (takich jak Linux) w rzeczywistości możliwe jest uzyskanie nieco bardziej niezawodnego rozwiązania poprzez usunięcie pliku tymczasowego natychmiast po jego otwarciu . Działa to, ponieważ uniksowe systemy plików pozwalają na usunięcie pliku ( dokładniej mówiąc, odłączenie go), gdy jest on nadal otwarty przez jeden lub więcej procesów. Dostęp do takich plików można uzyskać normalnie przez otwarty uchwyt pliku, a miejsce, które zajmują na dysku, zostanie odzyskane przez system operacyjny dopiero po ostatnim procesie trzymającym otwarte dojście do wyjścia pliku.

Oto najbardziej niezawodny i przenośny sposób, jaki znam, aby upewnić się, że plik tymczasowy zostanie poprawnie usunięty po zamknięciu programu:

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

W systemie Unixish uruchomienie tego powinno dać coś podobnego do następującego wyniku:

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.

podczas gdy w systemie Windows dane wyjściowe wyglądają nieco inaczej:

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.

Jednak w obu przypadkach plik tymczasowy nie powinien pozostać na dysku po zakończeniu działania programu.


Ps. Podczas testowania tego kodu w systemie Windows zauważyłem dość zaskakujący fakt: najwyraźniej samo pozostawienie niezamkniętego pliku tymczasowego wystarczy, aby zapobiec jego usunięciu . Oczywiście oznacza to również, że każda awaria, która zdarzy się, gdy plik tymczasowy jest używany, spowoduje, że pozostanie on nieusunięty, czego właśnie staramy się tutaj uniknąć .

AFAIK, jedynym sposobem uniknięcia tego jest upewnienie się, że plik tymczasowy jest zawsze zamykany za pomocą finallybloku. Oczywiście równie dobrze możesz usunąć plik z tego samego finallybloku. Nie jestem pewien, co, jeśli w ogóle cokolwiek, .deleteOnExit()mogłoby cię przez to przekonać.

Ilmari Karonen
źródło
1
Świetna odpowiedź. Inną ważną rzeczą, o której należy pamiętać deleteOnExit(), jest to, że jeśli jest wywoływana często (powiedzmy w systemie, który używa wielu nowych plików tymczasowych), prawdopodobnie spowoduje to wyciek pamięci (ponieważ musi zapamiętać wszystkie ścieżki, które muszą być usunięte).
Eyal Roth,
18

Jeśli nie wywołam tej delete()metody bezpośrednio, kiedy plik zostanie usunięty?

Nie zrobi tego, przynajmniej nie przez Javę. Jeśli chcesz, aby plik został usunięty po zakończeniu działania maszyny JVM, musisz zadzwonić tmp.deleteOnExit().

Ian Roberts
źródło
5

z: Jak usunąć plik tymczasowy w Javie

Plik tymczasowy służy do przechowywania mniej ważnych i tymczasowych danych, które zawsze powinny zostać usunięte po zamknięciu systemu . Najlepszą praktyką jest użycie do tego metody File.deleteOnExit ().

Na przykład,

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

Powyższy przykład utworzy plik tymczasowy o nazwie „abc.tmp” i usunie go, gdy program zostanie zakończony lub zamknięty .

Jeśli chcesz ręcznie usunąć plik tymczasowy , nadal możesz użyć funkcji File.delete ().

Grijesh Chauhan
źródło
Dlaczego jest to najlepsza praktyka?
Frans
3

Plik tymczasowy służy do przechowywania mniej ważnych i tymczasowych danych, które zawsze powinny zostać usunięte po zamknięciu systemu. Najlepszą praktyką jest użycie do tego metody File.deleteOnExit ().

Na przykład,

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

Powyższy przykład utworzy plik tymczasowy o nazwie „abc.tmp” i usunie go, gdy program zostanie zakończony lub zamknięty.

Juned Ahsan
źródło
-3

Jeśli chcesz, możesz ręcznie usunąć plik przed zakończeniem procesu, jednak po zakończeniu procesu plik zostanie również usunięty.

Jasper Ketelaar
źródło
3
Nie, zostanie ono usunięte tylko przy wyjściu, jeśli specjalnie zadzwoniszdeleteOnExit()
Ian Roberts