5

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

这是我到目前为止所拥有的:

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

我确信这不是最好的,但它现在可以完成工作。如果有人对如何以任何方式改进这一点有任何建议,我们非常欢迎提出建议。

4

5 回答 5

7

我想有一个小帮手/包装器,比如

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
    }
}

或者Closable通过 lambdas

public void myMethod(InputStream in, Path existingFile, String name) {
    try (Closeable closable = () -> Files.deleteIfExists(existingFile)) {
        // ...
    } catch (IOException e) {
        // 
    }
}
于 2015-12-02T18:40:53.197 回答
4

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

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

于 2015-12-02T17:49:37.820 回答
2

你可以在 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);
}
于 2016-09-28T10:38:25.513 回答
1

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

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

使用java.io.Filejava.nio.file.Path无法通过 try-with-resources 管理文件的生命周期。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...
           }
        }
    }
}
于 2015-12-02T18:15:54.503 回答
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();
    }
}
于 2016-07-25T11:37:38.570 回答