如何从文件系统获取std::string或char[]?

4

我有一个循环,遍历整个目录,我需要从每个文件获取路径以便使用。

这是我的方法:

#include <experimental/filesystem>

namespace fs = std::experimental::filesystem;

for (const auto & entry : fs::directory_iterator(sourceDir))
{
    if (fs::is_directory(entry))
        continue;
    StreamRAII iStream{ entry, StreamMode::READ_BINARY };
}

问题在于StreamRAII构造函数必须将std::string作为其第一个参数。
StreamRAII(const std::string& filename, const char *mode);

但是这里 const auto & entry : fs::directory_iterator(sourceDir)entry 的类型是 derectory_entry

问题是如何获取我的文件路径?如何将 derectory_entry 转换为 std::stringchar[]

P.S. 当我使用 cout 时,我可以看到我的文件路径...


很可能可以通过使用 std::filesystem::path 来实现这一点... 至于使用完全未知的 StreamRAII 的问题,你刚刚平静地提出了这个问题,我可以从路径文档中粘贴相关句子:"......路径可以隐式转换为 std::basic_strings,这使得可以将它们与其他文件 API 一起使用,例如作为 std::ifstream::open 的参数..." - Chef Gladiator
4个回答

11

derectory_entry有一个path()函数,返回一个包含文件路径名的std::filesystem::path。您可以使用它的string()函数从该路径获取std::string。这将使您的代码看起来像:

StreamRAII iStream{ entry.path().string(), StreamMode::READ_BINARY };

路径可以隐式地转换为std::basic_strings,这使得它们可以与其他文件API一起使用,例如作为std::ifstream::open的参数。 - Chef Gladiator
@ChefGladiator,你引用的内容是从哪里来的?std::filesystem::path没有operator std::string(),所以那不可能是正确的。 - NathanOliver
请访问以下链接以获取有关C++文件系统路径的详细信息:https://en.cppreference.com/w/cpp/filesystem/path截图链接:https://snag.gy/0hJEaD.jpg - Chef Gladiator
1
@ChefGladiator:那不是它的工作方式 - fstream本身采用std::filesystem::path。它未指定是否将字符串内部转换为路径、路径转换为字符串或其他内容。 - MSalters
我模糊地记得关于这个……“设计特性”……--https://learn.microsoft.com/en-us/cpp/standard-library/file-system-navigation?view=vs-2019---虽然现在有这句话-"路径对象可以隐式转换为std::wstring或std::string。" ..而且,如果我强制转换为std::string引用,VS2019确实会这样做...唉,我怀疑这是否优雅.. - Chef Gladiator
显示剩余7条评论

2
如果你想从文件中获取路径,请使用directory_iterator类的.path()方法。
如果你想从这个路径中获取一个字符串,只需在你的路径对象上使用.string()方法即可。"原始答案"

路径可以隐式地转换为std::basic_strings,这使得它们可以与其他文件API一起使用,例如作为std::ifstream::open的参数。 - Chef Gladiator

1
我不知道每个人都知道的StreamRAII是什么。这里是标准C++代码,可能会引导OP问题的正确答案方向。请注意,本文保留HTML标签。
// $ g++ prog.cc -Wall -Wextra -std=c++17
#include <iostream>
#include <fstream>
#include <string>
#include <filesystem>

struct StreamRAII final {
  StreamRAII(const std::string& filename, const char *mode)
 {
  using namespace std;
   cout << "\n\nInside StreamRAII(const std::string& filename, const char 
  *mode)\n\nFilename: "  << filename.c_str() << "\n\nmode: " << mode ;
}
};

int main()
{
  namespace fs = std::filesystem;

  for (const auto & entry : fs::directory_iterator("."))
  {
    if (fs::is_directory(entry))
       continue;
     StreamRAII iStream{ entry.path(), "StreamMode::READ_BINARY" };
  }

  return 0 ;   
 }

我查看了cppreference(en.cppreference.com/w/cpp/filesystem/path----snag.gy/0hJEaD.jpg),并使用g++编译,这很好用......但是最新更新的VS2019今天无法编译上述代码。


不,你必须使用.path().string(),否则会出现类型不匹配的错误。 - Sirop4ik
仅在 MSVC(最新和更新版本)下运行,而不是在 g++ 下运行...请参见 wandbox 的链接--https://wandbox.org/permlink/e9Bg8p1dHe6IW5ad - Chef Gladiator
那么你不应该使用.path().string()来实现可移植性吗? - NathanOliver
@NathanOliver 请看这里 https://godbolt.org/z/Pr9Und -- 由于 MSVC 的原因,我不得不这样做...在 MSVC 的情况下确实存在对 std::string 的隐式转换,但需要一些说服力... - Chef Gladiator
@ChefGladiator 我非常确定这段代码存在未定义行为。在Windows系统中,p1 隐式转换为 std::wstring。将其强制转换为 std::string 将违反严格别名规则。 - NathanOliver
@NathanOliver,我99.9999999%同意。不过,g++和clang都没有任何问题,也不需要“有毒转换”。我认为这个问题已经解决了。谢谢大家的观看 :) - Chef Gladiator

0
为了使这个平台与C++17无关,您必须确保StreamRAII接受std::filesystem::path或者std::string输入的合同是它必须是UTF-8编码的,然后您必须以这种方式使用它,在典型的POSIX系统上不会执行任何转换(但在其他系统上可能会执行转换(如MSVC))。但它在C++20中不起作用。
StreamRAII iStream{ entry.path().u8string(), StreamMode::READ_BINARY };

如果您无法控制StreamRAII,则只能将路径转换为std::string(如其他人所述),并祈祷它仍然可以正常工作。这将在C++20中编译,但是否有效取决于系统(可能)。

StreamRAII iStream{ entry.path().string(), StreamMode::READ_BINARY };

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接