查找有关try catch块中file.delete()方法的解释



尝试制作一个简单的'cut'程序来跨文件夹移动文件。在它复制后,它应该删除源文件,但它忽略fileLocation.delete();方法在try块中。如果我把它放在'finally'块中,它可以工作,并且在程序中的其他任何地方,在它复制文件之后,它也可以工作,但这对它以这种方式工作没有意义,即使出了问题,源也会被删除。我的问题是为什么它忽略它,我无法在网上找到答案。谢谢你。

File fileLocation = new File("C:\fileLocation\picture.png");
File fileDestination = new File("C:\fileDestination\picture.png");
try(FileInputStream input = new FileInputStream(fileLocation);
FileOutputStream output = new FileOutputStream(fileDestination)) {
byte[] buffer = new byte[1024];
int length;
while((length = input.read(buffer)) > 0) {
output.write(buffer,0, length);
}
fileLocation.delete();
} catch(IOException exc) {
System.out.println(exc.getMessage());
}
try(FileInputStream input = new FileInputStream(fileLocation);
... ) {
// ..
fileLocation.delete();
}

此时,input仍然是打开的,所以您不能删除它所引用的文件。

根据语言规范中try-with-resources的定义,try-with-resources语句上的finally块将在资源关闭后执行。因此,将删除放在finally块中意味着它可以成功。


与其将其放在finally中(无论是否抛出异常都会发生),不如将资源拆分为两个尝试使用资源块,并在完成input后删除:

try (FileOutputStream output = ...) {
try (FileInputStream input = new FileInputStream(fileLocation)) {
// ..
}
// input is now closed.
fileLocation.delete();
} catch(IOException exc) {
System.out.println(exc.getMessage());
}

现在,只有在output的try-with-resources块(包括input的try-with-resources块)中没有抛出IOException时,fileLocation才会被删除。

或者,如果您想在output关闭之前不删除它:将IOException捕获移动到周围的try/catch块中(而不是try-with-resources):

try {
try (FileOutputStream output = ...;
FileInputStream input = ...) {
// ..
}
// input and output are now both closed.
fileLocation.delete();
} catch(IOException exc) {
System.out.println(exc.getMessage());
}

当然,移动文件更好的方法是使用实用程序方法来移动文件,例如

Files.move(fileLocation.toPath(), fileDestination.toPath(), CopyOption.REPLACE_EXISTING);

您使用了错误的API。File.delete()是众所周知的坏API设计。

这就是它不好的地方,也是为什么它解释了你的困惑:不像任何其他API,如果delete()删除失败,它不会抛出任何异常。相反,它返回false。这在三个重要方面是不好的:

  • un-java-like。很少有api能做到这一点;他们中的绝大多数人会扔东西。
  • 很容易"忘记"。只是自己编写x.foo();,其中foo()是返回某些东西的任何方法(即具有非void返回类型),这是完美的java。这是java的for:运行这个方法,然后获取结果并将其扔进垃圾桶。您在这里已经这样做了:调用delete()并忽略结果。对于delete(),这实际上是不行的,除非您打算编写的代码有效地表示:">try删除该路径。无论成功与否,都要继续执行代码。这通常不是你想要的。
  • 如果确实出错,则不可能delete()方法告诉你除了"我无法完成它"之外的任何细节。没有办法使用消息或某种异常类型来为您清除问题。

解决方案很简单。停止使用这种方法。把它放在列表中:这个方法不应该再在java代码中调用。如果你在维护一些有15年历史的东西,我想这很好,但快速重构来摆脱它也不会错。

很棒!那么我应该用哪个新符号呢?

java.nio.file包中的path/files API。

替换:

File f = new File("a/b/c.txt");
f.delete();

:

Path p = Paths.get("a/b/c.txt");
Files.delete(p);

不像file.delete(),Files.delete(path)将抛出一个异常,如果不能执行删除。然后,该异常包含有关原因的适当信息。例如,因为文件不存在,或者因为您没有对底层目录的写访问权限,或者因为文件系统是以只读方式挂载的,等等。

新的File API也更加强大。例如,它可以正确地处理链接或备用文件系统。它也有更多的方法。例如,它有Files.move方法,在这里可能特别有用。

仅供参考,为什么我的删除操作失败?

可能是因为您自己的进程仍然打开着文件。在某些操作系统/文件系统组合(特别是在windows和NTFS上),您不能删除打开的文件。即使你自己的进程仍然打开着文件

如果你使用Files.delete(),你会得到一个异常,消息会让你更接近那个结论,而不是'delete()调用返回false',幸运的是。

最新更新