C++ std::filesystem::filesystem_error 异常试图读取系统卷信息等

标签 c++ exception filesystems c++17

我正在尝试解决在尝试递归遍历根驱动器(如 C:、D: 等)中的所有文件时抛出的异常。我在 Mingw64 上使用 GCC 编译器版本 9.3.0。

我在尝试读取系统卷信息时遇到 std::filesystem::filesystem_error,示例输出:

Checking "D:\\System Volume Information"
filesystem error: cannot increment recursive directory iterator: Invalid argument

代码片段:

try {
     for (auto& p : fs::recursive_directory_iterator(dp,  fs::directory_options::skip_permission_denied)) {
            
         cout << "Checking " << p.path() << endl;
         string path = p.path().string();

          if (fs::is_regular_file(p) && p.path().extension() == ".xyz") {
              files.push_back(p.path().string());
          }
      }
}
catch (fs::filesystem_error &e) {
   // How to go back, skip this, and resume?
   cerr << e.what() << endl;
}

我想做的是跳过这些异常。有人知道怎么做吗?

谢谢!

最佳答案

由于您的错误是指递增 recursive_filesystem_iterator,该错误似乎来自 for 语句本身,而不是您的后续代码。 for 语句在内部对 recursive_filesystem_iterator 执行递增 (operator++)。

对我来说,这感觉像是 recursive_filesystem_iterator 实现中的一个错误,而您的代码应该无一异常(exception)地工作。但是仔细阅读该标准,我认为实现中存在足够多的歧义,可以说您看到的行为仍然符合标准。

我没有 c++17 标准的官方拷贝,所以我在这里提供的引用是免费提供的草案 n4659.pdf .

30.10.2.1 Posix 一致性,它说

Implementations that do not support exact POSIX behavior are encouraged to provide
behavior as close to POSIX behavior as is reasonable given the limitations of actual
operating systems and file systems. If an implementation cannot provide any reasonable
behavior, the implementation shall report an error as specified in 30.10.7. [Note:This
allows users to rely on an exception being thrown or an error code being set when an
implementation cannot provide any reasonable behavior.— end note]

Implementations are not required to provide behavior that is not supported by a
particular file system. [Example: The FAT file system used by some memory cards, camera
memory, and floppy disks does not support hard links, symlinks, and many other features
of more capable file systems, so implementations are not required to support those
features on the FAT file system but instead are required to report an error as described
above.— end example]

因此,如果底层文件系统不允许您这样做,则尝试迭代到 D:\System Volume Information 可能会失败并引发异常。

您的构造函数指定directory_options::skip_permission_denied。我觉得这应该足以避免异常。

30.10.14.1 recursive_directory_iterator members for operator++ 中说:

...then either directory(*this)->path() is recursively iterated into or, if
    (options() & directory_options::skip_permission_denied) != directory_options::none
and an error occurs indicating that permission to access directory(*this)->path() is denied,
then directory(*this)->path() is treated as an empty directory and no error is reported.

您得到的实际异常并没有说“权限被拒绝”,所以我想可以说 skip_permission_denied 选项不适用于它。这将允许 operator++ 的实现在这种情况下抛出异常。我不喜欢这种解释,因为 skip_permission_denied 的整个想法似乎是为了避免这样的异常。但这不取决于我。 :)

除了尝试将缺陷提交回标准库实现之外,您还能做什么?或许您可以编写一个老式的 for 循环,并在 recursive_filesystem_iterator 上使用 increment 方法。 increment 方法返回错误代码而不是抛出异常。所以你的代码看起来像这样:

auto iter = fs::recursive_directory_iterator(dp, fs::directory_options::skip_permission_denied);
auto end_iter = fs::end(iter);
auto ec = std::error_code();
for (; iter != end_iter; iter.increment(ec))
{
    if (ec)
    {
        continue;
    }

    // The rest of your loop code here...
}

我认为上面的内容看起来很合理,但绝对需要测试以确保没有出现无限循环之类的奇怪极端情况。实际上我不太确定是否需要 continue 东西,但您可能想尝试一下。

最后,当您遇到 filesystem_error 时,除了 e.what() 之外,您还可以打印出 e.path1.native() >。我认为您已经基本了解该信息,因为您正在循环中打印路径。但在某些情况下它可能会提供更多信息。

关于C++ std::filesystem::filesystem_error 异常试图读取系统卷信息等,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62988629/

相关文章:

c++ - N 选择 k 为大 n 和 k

c++ - LLVM:将全局变量链接类型设为 linkonce

javax.crypto.IllegalBlockSizeException : Input length not multiple of 16 bytes

java - 如何在 Java 7 中可移植地获取文件存储的 block 大小?

asp-classic - FileSystemObject 是否知道文件不完整?

c++ - 在扩展MAPI中更改帐户

c++ - 如何将 Eigen::SparseMatrix 包装在预先存在的 3 标准压缩行/列数组上

c# - 从 bool 方法捕获异常消息

java - 正确的辅助方法异常抛出

linux - 命令输出在重定向时被破坏