【问题标题】:C++ std::filesystem::filesystem_error exception trying to read system volume information, etcC++ std::filesystem::filesystem_error 异常试图读取系统卷信息等
【发布时间】:2020-07-20 19:36:18
【问题描述】:

我正在尝试解决在尝试递归遍历根驱动器中的所有文件(如 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

代码sn-p:

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;
}

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

谢谢!

【问题讨论】:

  • 看起来我必须以某种方式在它周围放置一个包装器,例如:Ignoring an exception。仍然不清楚一旦遇到异常或从错误中恢复如何恢复处理。
  • 在循环中使用另一个 try 块怎么样?

标签: c++ exception filesystems c++17


【解决方案1】:

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

对我来说,这感觉像是recursive_filesystem_iterator 的实现中的一个错误,您的代码应该可以正常工作。但是仔细阅读标准,我想有足够的模糊性让一个实现说你看到的行为仍然符合标准。

我没有 c++17 标准的正式副本,所以我在这里给出的参考是免费提供的草案 n4659.pdf

30.10.2.1 Posix conformance,上面写着

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 中为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()。我认为您已经大多知道该信息,因为您正在打印循环中的路径。但在某些情况下它可能会提供更多信息。

【讨论】:

  • 谢谢埃里克!您可能是正确的,因为存在足够多的歧义以使该行为看起来严格正确。我确实想,嘿,如果不是权限被拒绝,那又是什么?太奇怪了,它让我觉得带有 mingw64 的标准 C++ 在某种程度上被破坏了。在我测试更多之前不确定,但我必须让它工作,所以感谢上帝的 Boost! :)
  • 这毕竟是 Windows,所以如果 System Volume Information 是“特殊的”,我不会感到惊讶。所以也许它上面有权限位,如果它是其他文件,允许你获得权限,但是操作系统仍然不允许你访问它。那么标准库就得想办法处理那个错误了,也许mingw64标准库做的不是很好呢?或类似的东西。显然我只是在这里推测。
猜你喜欢
  • 1970-01-01
  • 2018-09-30
  • 1970-01-01
  • 2010-09-25
  • 1970-01-01
  • 1970-01-01
  • 2011-04-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多