尝试使用资源处理临时文件
Handle temporary file in try with resources
对于我的应用程序,我必须编写一个方法,将 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());
}
}
我敢肯定它不是最好的,但它现在可以完成工作。如果有人对如何以任何方式改进这一点有任何建议,我们非常欢迎。
Try-with-resource 只是在实现接口 java.lang.AutoCloseable
的 类 上调用关闭方法。没有什么可以阻止您创建实现 AutoCloseable
并在调用 close() 时删除自身的 File 实现。
您也可以在文件上调用 deleteOnExit()
让 JVM 在文件退出时将其删除。仅当您可以等到 JVM 完成删除临时文件时,这才适用。对于像 Java webapp 这样的长 运行 JVM,这可能不是一个好主意。
Files.createTempFile 允许您在 JVM 的默认临时目录中创建一个临时文件。这并不意味着文件会自动删除或使用 File.deleteOnExit()
标记为删除。开发者负责管理临时文件的生命周期。
文件名是安全漏洞的载体。仅使用名称在 UI 中显示以进行验证和反馈。不要使用不受信任的用户输入文件名。
使用 java.io.File or java.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...
}
}
}
}
我想像
这样的小帮手/包装器
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) {
//
}
}
我有一个类似的问题,就是临时 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();
}
}
您可以在 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);
}
对于我的应用程序,我必须编写一个方法,将 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());
}
}
我敢肯定它不是最好的,但它现在可以完成工作。如果有人对如何以任何方式改进这一点有任何建议,我们非常欢迎。
Try-with-resource 只是在实现接口 java.lang.AutoCloseable
的 类 上调用关闭方法。没有什么可以阻止您创建实现 AutoCloseable
并在调用 close() 时删除自身的 File 实现。
您也可以在文件上调用 deleteOnExit()
让 JVM 在文件退出时将其删除。仅当您可以等到 JVM 完成删除临时文件时,这才适用。对于像 Java webapp 这样的长 运行 JVM,这可能不是一个好主意。
Files.createTempFile 允许您在 JVM 的默认临时目录中创建一个临时文件。这并不意味着文件会自动删除或使用 File.deleteOnExit()
标记为删除。开发者负责管理临时文件的生命周期。
文件名是安全漏洞的载体。仅使用名称在 UI 中显示以进行验证和反馈。不要使用不受信任的用户输入文件名。
使用 java.io.File or java.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...
}
}
}
}
我想像
这样的小帮手/包装器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) {
//
}
}
我有一个类似的问题,就是临时 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();
}
}
您可以在 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);
}