【问题标题】:Most efficient way to read an entire file into vector of lines将整个文件读入行向量的最有效方法
【发布时间】:2016-01-02 21:28:08
【问题描述】:

我正在尝试找到一种更有效的方法将整个文件读入行向量,定义为std::vector<std::string>

目前,我写的很幼稚:

std::ifstream file{filepath};
std::vector<std::string> lines;

std::string line;
while(std::getline(file, line)) lines.push_back(line);

但感觉push_back 中的额外副本和每行的向量重新分配对效率极为不利,我正在寻找更现代的 c++ 类型的方法,such as using stream buffer iterators when copying bytes

std::ifstream file{filepath};
auto filesize = /* get file size */;
std::vector<char> bytes;
bytes.reserve(filesize);
bytes.assign(std::istreambuf_iterator{file}, istreambuf_iterator{});

有没有这样的方法可以将文本文件逐行读取到向量中?

【问题讨论】:

  • 如果您使用std::move(line)push_back 将不会复制。
  • @JonathanPotter 在move 之后再次使用对象?不喜欢那样。不过,我会使用emplace_back
  • 流迭代器方法在我的测试中非常慢。为了获得最大速度,我会尝试将整个文件读入一个预先分配的向量中,然后从那里将其拆分为单独的字符串。
  • @CoffeeandCode move 保证将移出的对象保持在一致的状态,所以我没有看到问题。
  • @Galik:要么重新分配旧字符串,要么在向量中分配新字符串,对此您无能为力。至少你没有复制实际的字符。

标签: c++ vector fstream c++14


【解决方案1】:

有一种非常有趣且相对较新的方法 - 范围。您可以阅读 Eric Niebler 的非常有趣的文章:

Out Parameters, Move Semantics, and Stateful Algorithms 关于快速getlines 替代方案

Input Iterators vs Input Ranges

【讨论】:

    【解决方案2】:

    以下代码可能会起作用。

    struct FileContents
    {
       // Contents of the file.
       std::string contents;
    
       // Each line consists of two indices.
       struct line { std::string::size_type begin; std::string::size_type end;};
    
       // List of lines.
       std::vector<line> lines;
    };
    
    void readFileContents(std::string const& file,
                          FileContents& fileContents)
    {
       std::ifstream ifs(file);
       if ( !ifs )
       {
          // Deal with error.
          return;
       }
    
       // Get the size of the file.
       ifs.seekg(0, std::ios::end);
       std::fstream::pos_type size = ifs.tellg();
    
       // Reserve space to read the file contents.
       fileContents.contents.assign(static_cast<std::string::size_type>(size), '\0');
    
       // Read the file contents.
       ifs.seekg(0, std::ios::beg);
       ifs.read(&fileContents.contents[0], size);
       ifs.close();
    
       // Divide the contents of the file into lines.
       FileContents::line line = {0, 0};
       std::string::size_type pos;
       while ( (pos = fileContents.contents.find('\n', line.begin)) != std::string::npos )
       {
          line.end = pos+1;
          fileContents.lines.push_back(line);
          line.begin = line.end;
       }
       line.end = fileContents.contents.size();
       if ( line.begin < fileContents.contents.size() )
       {
          fileContents.lines.push_back(line);
       }
    }
    

    【讨论】:

      猜你喜欢
      • 2016-02-29
      • 1970-01-01
      • 1970-01-01
      • 2012-09-28
      • 1970-01-01
      • 2011-06-06
      • 1970-01-01
      • 1970-01-01
      • 2012-08-06
      相关资源
      最近更新 更多