我可以信任Files中的方法会在预期时抛出NoSuchFileException吗?

时间:2015-03-17 05:34:31

标签: java file-io nio

java.nio.file.Files API相对于旧的java.io.File类是一个非常好的改进,但有一个细节让我觉得奇怪;除delete()之外,没有任何方法文档可能会引发NoSuchFileException,甚至delete()表示这是可选的。

我希望能够区分由于丢失文件和其他IO问题导致的故障,但似乎无法保证这一点。

如果在两个操作之间创建文件,则事先调用Files.exists()之类的替代方法会冒着竞争条件的风险。

我可以预期Files中的方法会在适当的时候提出NoSuchFileException吗?如果是这样,这在哪里记录?如果没有,我如何安全地确定失败是由于文件丢失?


示例:在带有Java 7.0.02的Windows 7上,Files.readAllLines()方法确实引发了NoSuchFileException,尽管没有明确记录这样做:

Files.readAllLines(Paths.get("foo"), StandardCharsets.UTF_8)
java.nio.file.NoSuchFileException: foo
  at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:79)
  at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97)
  at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102)
  at sun.nio.fs.WindowsFileSystemProvider.newByteChannel(WindowsFileSystemProvider.java:229)
  at java.nio.file.Files.newByteChannel(Files.java:315)
  at java.nio.file.Files.newByteChannel(Files.java:361)
  at java.nio.file.spi.FileSystemProvider.newInputStream(FileSystemProvider.java:380)
  at java.nio.file.Files.newInputStream(Files.java:106)
  at java.nio.file.Files.newBufferedReader(Files.java:2660)
  at java.nio.file.Files.readAllLines(Files.java:2993)

2 个答案:

答案 0 :(得分:1)

一般来说:不,你不能相信java.nio.file.Files中的方法在预期时抛出NoSuchFileException,但你可以验证。

从堆栈跟踪中可以看出,Files使用FileSystemProvider来执行文件操作。 FileSystemProvider实现受到限制(如WindowsFileSystemProvider),然后使用大量本机(C)代码。例如,我跟踪了NoSuchFileException到依赖于操作系统的WindowsException来报告ERROR_FILE_NOT_FOUNDERROR_PATH_NOT_FOUND。另一个示例是newInputStream路由,从ChannelInputStreamWindowsChannelFactoryWindowsNativeDispatcher.c,最终调用本机Windows函数CreateFileW
鉴于仅涉及Windows的代码量,我不知道如何使用代码herehere来实现相同的工作方式。

根据我的经验,Linux(Posix)文件系统行为非常一致,但Windows(NT)文件系统行为不是:我不认为Windows 7的行为与Windows 8完全相同。

最后,关于竞争条件的评论:我知道没有文件系统保证目录中列出的文件实际存在(某些文件可能已被删除,尤其是当使用多个线程对同一目录中的文件进行操作时)。根据我的经验,预先使用像Files.exists()这样的方法是个坏主意,除非您要分配大量资源(例如创建连接以上传文件)。处理文件时,最好假设一切正常并捕获异常,然后尝试确定错误。例如。在读取文件时,打开它而不检查文件是否存在,如果发现错误,请检查文件是否存在以开始。这可以节省大量的I / O操作,从而有助于提高性能。

答案 1 :(得分:0)

Files类提供两种删除方法

删除(路径)方法删除文件或在删除失败时抛出异常。例如,如果文件不存在,则抛出NoSuchFileException。您可以捕获异常以确定删除失败的原因,如下所示:

try {
    Files.delete(path);
} catch (NoSuchFileException x) {
    System.err.format("%s: no such" + " file or directory%n", path);
} catch (DirectoryNotEmptyException x) {
    System.err.format("%s not empty%n", path);
} catch (IOException x) {
    // File permission problems are caught here.
    System.err.println(x);
}

deleteIfExists(Path)方法也会删除该文件,但如果该文件不存在,则不会抛出任何异常。当你有多个线程删除文件并且你不想仅仅因为一个线程首先抛出异常时,静默失败很有用。

注意: NoSuchFileException DirectoryNotEmptyException 是Java 7中引入的新例外。