对于我的应用程序,我必须编写一个以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());
}
}
我确定它不是最好的,但它现在可以胜任。如果有人对如何以任何方式改进这一点有任何建议,那么建议非常受欢迎。
答案 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.File或java.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();
}
}