在C++中获取文本文件的第n行

8
我需要读取文本文件的第n行(例如:textfile.findline(0)会找到使用ifstream textfile加载的文本文件的第一行)。这是否可能?我不需要将文件内容放入数组/向量中,我只需要将文本文件的特定行分配给一个变量(具体来说是一个整数)。
附言:我正在寻找最简单的解决方案,不需要使用任何大型外部库(例如Boost)。提前感谢。

你可以将其放入循环中并使用计数器:https://dev59.com/AG865IYBdhLWcg3wQMMD#3910610 - 但是如果你需要执行多次查找,你可能希望将整个文件内容存储在内存中,这样会快得多。 - jweyrich
4个回答

8
这个怎么样?
std::string ReadNthLine(const std::string& filename, int N)
{
   std::ifstream in(filename.c_str());

   std::string s;
   //for performance
   s.reserve(some_reasonable_max_line_length);    

   //skip N lines
   for(int i = 0; i < N; ++i)
       std::getline(in, s);

   std::getline(in,s);
   return s; 
}

6
如果您想读取第n行的开头,可以使用stdin :: ignore跳过前n-1行,然后从下一行开始读取并赋值给变量。
template<typename T>
void readNthLine(istream& in, int n, T& value) {
  for (int i = 0; i < n-1; ++i) {
    in.ignore(numeric_limits<streamsize>::max(), '\n');
  }
  in >> value;
}

2

Armen的解决方案是正确的答案,但我想提出一个基于jweyrich的缓存思想的替代方案。无论好坏,这个方案在构建时读取整个文件,但仅保存换行符的位置(不存储整个文件,因此可以处理大型文件)。然后,您只需调用ReadNthLine,它将立即跳转到该行,并读取您想要的一行。另一方面,只有在您想一次获取一部分行且行号在编译时未知的情况下,这种方式才是最佳的。

class TextFile {
    std::ifstream file_stream;
    std::vector<std::ifstream::streampos> linebegins;
    TextFile& operator=(TextFile& b) = delete;
public;
    TextFile(std::string filename) 
    :file_stream(filename) 
    {
        //this chunk stolen from Armen's, 
        std::string s;
        //for performance
        s.reserve(some_reasonable_max_line_length); 
        while(file_stream) {
            linebegins.push_back(file_stream.tellg());
            std::getline(file_stream, s);
        }
    }
    TextFile(TextFile&& b) 
    :file_stream(std::move(b.file_stream)), 
    :linebegins(std::move(b.linebegins))
    {}
    TextFile& operator=(TextFile&& b) 
    {
        file_stream = std::move(b.file_stream);
        linebegins = std::move(b.linebegins);
    }
    std::string ReadNthLine(int N) {
        if (N >= linebegins.size()-1)
            throw std::runtime_error("File doesn't have that many lines!");
        std::string s;
        // clear EOF and error flags
        file_stream.clear();
        file_stream.seekg(linebegins[N]);
        std::getline(file_stream, s);
        return s;
    }
};

聪明!这是我认为最好的解决方案。 - jweyrich
当以文本模式打开文件并保存为MS-Windows文件格式时,使用seekg()跳转到任意位置会出现问题。这是由于使用了不同的行尾终止符。如果文件以unix文件格式保存(在vim中执行:set ff=unix),则Mooning Duck的解决方案将有效。您可以在此处找到相关讨论:“problem with seekg”。 - npras
@npras:理论上这个问题不应该存在,因为我并没有自己计算偏移量,而是使用了tellg(),即使在Windows上也应该与seekg匹配。 - Mooing Duck

1

这是完全可能的。在第n行之前有(n-1)个'\n'字符。读取行直到找到您要查找的行。您可以即时执行此操作,而无需存储除当前正在考虑的行以外的任何内容。


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