使用资源处理临时文件

时间:2015-12-02 17:36:45

标签: java try-with-resources java.nio.file

对于我的应用程序,我必须编写一个以InputStream为参数的方法,将内容写入临时文件,执行一些操作并最终删除临时文件。

这是我到目前为止所做的:

public void myMethod(InputStream in, String name) {
    //...
    Path path = Paths.get("./tmp/benchmarks/" + name + ".zip")

    try {
        Files.copy(in, path);
        //operations...
    } catch (IOException e) {
        //error handling for copy...
    } finally {
        try {
            Files.delete(path));
       } catch (IOException e) {
           //error handling for delete...
       }
    }
    //...
}

它完成了这项工作,但它看起来也很丑陋。我想知道是否有某种方法可以使用try-with-resources更优雅地处理这个问题。 有可能吗?

更新:我在十分钟内写了一个即时解决方案。它看起来像这样:

public class TemporaryFileHandler implements AutoCloseable {

    private File file;

    public TemporaryFileHandler(final InputStream in, final Path path) throws IOException {
        Files.copy(in, path);
        this.file = new File(path.toString());
    }

    public File getFile() { return file; }

    @Override
    public void close() throws IOException {
        Files.delete(file.toPath());
    }
}

我确定它不是最好的,但它现在可以胜任。如果有人对如何以任何方式改进这一点有任何建议,那么建议非常受欢迎。

5 个答案:

答案 0 :(得分:5)

我认为使用像

这样的小助手/包装器
public class AutoDeletingTempFile implements AutoCloseable {

    private final Path file;

    public AutoDeletingTempFile() throws IOException {
        file = Files.createTempFile(null, null);
    }

    public Path getFile() {
        return file;
    }

    @Override
    public void close() throws IOException {
        Files.deleteIfExists(file);
    }
}

关闭并删除它包装的文件得到一个很好的短语法:

public void myMethod(InputStream in, String name) {
    try (AutoDeletingTempFile wrapper = new AutoDeletingTempFile()) {
        //Files.copy(in, wrapper.getFile());
        //operations...
    } catch (IOException e) {
        //error handling for copy...
        // + temp file creation
    }
}

或通过lambdas整洁的小Closable

public void myMethod(InputStream in, Path existingFile, String name) {
    try (Closeable closable = () -> Files.deleteIfExists(existingFile)) {
        // ...
    } catch (IOException e) {
        // 
    }
}

答案 1 :(得分:4)

Try-with-resource只调用实现java.lang.AutoCloseable接口的类的close方法。没有什么可以阻止您创建实现AutoCloseable的File实现,并在调用close()时删除它自己。

您还可以在文件上调用deleteOnExit()以让JVM在退出时将其删除。只有在等待JVM完成删除临时文件之后,这才合适。对于像Java webapp这样长期运行的JVM,这可能不是一个好主意。

答案 2 :(得分:1)

Files.createTempFile允许您在JVM的默认临时目录中创建临时文件。这并不意味着使用File.deleteOnExit()自动删除文件或将其标记为删除。开发人员负责管理临时文件的生命周期。

该文件的名称是安全漏洞的向量。仅使用UI中的显示名称进行验证和反馈。不要对文件名使用不受信任的用户输入。

使用java.io.Filejava.nio.file.Path尝试使用资源无法管理文件的生命周期。 InputStream可以通过try-with-resources进行管理。

public void myMethod(InputStream in) {
    Path path = null;

    try (InputStream stream = in) {
        path = Files.createTempFile(null, ".zip");
        Files.copy(stream, path);
    } catch (IOException e) {
        //error handling for copy...
    } finally {
        if (path != null) {
            try {
                Files.delete(path));
           } catch (IOException e) {
               //error handling for delete...
           }
        }
    }
}

答案 3 :(得分:1)

你可以在java 8中做这样的事情:

Path path = Files.createTempFile("temp-", ".tmp");
try (Closeable onClose = () -> Files.delete(path)) {
    ...
}

但这与以下内容完全相同:

Path path = Files.createTempFile("temp-", ".tmp");
try {
    ...
} finally {
    Files.delete(path);
}

答案 4 :(得分:0)

我遇到了类似的问题,其中没有删除临时ZIP文件。我的假设是在代码尝试删除临时文件之前没有关闭输出流。

我的解决方案使用嵌套式尝试,并不优雅,但它应该保证事先关闭流。

<强>之前

File out = // get file;

try(
    FileOutputStream fos = new FileOutputStream(out);
    ZipOutputStream zos =  new ZipOutputStream(fos);
){
    // Create ZIP file and deliver to client using HTTPServletResponse
}
finally{
    if (out != null){
        out.delete();
    }
}

<强>后

File out = // get file;

try{
    try(
        FileOutputStream fos = new FileOutputStream(out);
        ZipOutputStream zos =  new ZipOutputStream(fos);
    ){
        // Create ZIP file and deliver to client using HTTPServletResponse
    }
}
finally{
    if (out != null){
        out.delete();
    }
}