Java 临时文件何时被删除?

假设我用以下方法在Java中创建一个临时文件

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

如果我不显式调用该方法,何时会删除该文件?delete()

作为一种直觉,它可能是当JVM终止时,或者更早(由垃圾回收器),或更晚(通过某些操作系统扫描进程)。


答案 1

该文件不会自动从 JavaDoc 中删除:

此方法仅提供临时文件工具的一部分。若要安排自动删除由此方法创建的文件,请使用 deleteOnExit() 方法。

所以你必须显式调用 deleteOnExit()

请求在虚拟机终止时删除此抽象路径名所表示的文件或目录。


答案 2

正如其他答案所指出的,除非您明确请求,否则使用File.createTempFile()创建的临时文件不会自动删除。

执行此操作的通用可移植方法是在对象上调用 .deleteOnExit(),这将在 JVM 终止时安排删除文件。但是,此方法的一个小缺点是,它仅在 VM 正常终止时才有效。在异常终止(即 VM 崩溃或 VM 进程强制终止)时,文件可能仍未删除。File

在Unixish系统(如Linux)上,实际上可以通过在打开临时文件后立即将其删除来获得更可靠的解决方案。这是有效的,因为Unix文件系统允许删除文件(确切地说,是取消链接的),而它仍然被一个或多个进程保持打开状态。此类文件可以通过打开的文件句柄正常访问,并且只有在最后一个进程对文件退出保持打开句柄后,操作系统才会在磁盘上占用它们的空间。

因此,以下是我所知道的最可靠和最便携的方法,以确保在程序退出后临时文件将被正确删除:

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

在Unixish系统上,运行它应该产生类似于以下输出的内容:

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.

而在Windows上,输出看起来略有不同:

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.

但是,在任一情况下,程序结束后,临时文件都不应保留在磁盘上。


附言在Windows上测试此代码时,我观察到一个相当令人惊讶的事实:显然,仅将临时文件保持未关闭就足以防止其被删除。当然,这也意味着在使用临时文件时发生的任何崩溃都会导致它保持未删除状态,这正是我们在这里试图避免的。

AFAIK,避免这种情况的唯一方法是确保临时文件始终使用块关闭。当然,您也可以在同一块中删除该文件。我不确定使用什么,如果有的话,实际上会让你超过这一点。finallyfinally.deleteOnExit()