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

dim*_*414 9 java file-io nio

java.nio.file.FilesAPI是在旧的一个非常好的改善java.io.File类,但一个细节令我奇怪的; 除了delete()没有可能抛出的方法文档,NoSuchFileException甚至delete()说这是可选的.

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

Files.exists()如果在两个操作之间创建文件,则事先调用等的替代方法存在竞争条件.

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


示例:在带有Java 7.0.02的Windows 7上,该Files.readAllLines()方法确实会引发一个NoSuchFileException,但是没有明确记录这样做:

Files.readAllLines(Paths.get("foo"), StandardCharsets.UTF_8)
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)

van*_*kel 1

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

从堆栈跟踪中可以看到,Files使用FileSystemProvider来执行文件操作。这些FileSystemProvider实现受到限制(如WindowsFileSystemProvider),并且反过来使用大量本机 (C) 代码。例如,我跟踪NoSuchFileException到依赖操作系统报告 a或 的WindowsException。另一个示例是从ChannelInputStreamWindowsChannelFactoryWindowsNativeDispatcher.c的路线,最终调用本机 Windows 函数CreateFileW。 考虑到 Windows 所涉及的代码量,我不知道如何才能相信它对于使用此处此处代码的 Linux 也能同样工作。ERROR_FILE_NOT_FOUNDERROR_PATH_NOT_FOUNDnewInputStream

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

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