C++ 程序应显示文件的最后5行,但不能处理大文件

C++ 程序应显示文件的最后5行,但不能处理大文件,c++,linux,C++,Linux,我写了一个程序,应该打印文件的最后5行,但是老师创建了一个4 GB的文件,程序坏了。如何重写程序,使其能够处理非常大的文件 一个可能的解决方案是逐字符读取文件,但我不知道如何执行 这是c++程序代码 #include <iostream> #include <fstream> #include <string> using std::ifstream; using std::cout; using std::string; using std::getl

我写了一个程序,应该打印文件的最后5行,但是老师创建了一个4 GB的文件,程序坏了。如何重写程序,使其能够处理非常大的文件

一个可能的解决方案是逐字符读取文件,但我不知道如何执行

这是c++程序代码

#include <iostream>

#include <fstream>

#include <string>

using std::ifstream;
using std::cout;
using std::string;
using std::getline;

int main(int argc, char * argv[], char * env[]) {
  setlocale(LC_ALL, "");
  int i;
  string line;

  if (argc == 3) {

    string filename = argv[1];

    ifstream myfile(filename);
    string n = argv[2];

    int nn = atoi(n.c_str());

    string line, buffer[nn];
    const size_t size = sizeof buffer / sizeof * buffer;
    size_t i = 0;

    while (getline(myfile, line)) {
      buffer[i] = line;
      if (++i >= size) {
        i = 0;
      }
    }

    for (size_t j = 0; j < size; ++j) {
      cout << buffer[i] << "\n";
      if (++i >= size) {
        i = 0;
      }
    }
    //return 0;

  }

}
#包括
#包括
#包括
使用std::ifstream;
使用std::cout;
使用std::string;
使用std::getline;
int main(int argc,char*argv[],char*env[]{
setlocale(LC_ALL,“”);
int i;
弦线;
如果(argc==3){
字符串文件名=argv[1];
ifstream myfile(文件名);
字符串n=argv[2];
int nn=atoi(n.c_str());
字符串行,缓冲区[nn];
const size\u t size=sizeof buffer/sizeof*buffer;
尺寸i=0;
while(getline(myfile,line)){
缓冲区[i]=行;
如果(++i>=大小){
i=0;
}
}
对于(尺寸j=0;jcout问题一定是4GB文件中的大行。您的解决方案缓冲(或稍后删除)每一行,并且至少有一行可能太长,无法在您运行的机器中缓冲,从而导致程序崩溃

当达到
nn+1
的计数时,应从计算换行数的末尾开始读取文件,并停止并输出其余的if。当需要处理大行时,缓冲最后的
nn
行不是一个好的选择

下面是一个可以帮助您的解决方案片段:

array<char, 64 * 1024> buffer; // 64kb of buffer

size_t nn = atoi(n.c_str()); 

myfile.seekg(0, ios_base::end); 

unsigned int nlcount = 0; 
size_t length = myfile.tellg(); 
size_t oldpos = length; 

while (myfile.tellg() > 0) { 
  size_t newpos = oldpos - min(oldpos, buffer.size()); 
  myfile.seekg(newpos); 
  size_t rdsize = oldpos - newpos; 
  myfile.read(buffer.data(), rdsize); 
  if (!myfile) { 
    cerr << "failed while looking for newlines\n"; 
    return 1; 
  } 
  auto rit = buffer.rbegin() + (buffer.size() - rdsize); 
  while (rit != buffer.rend() && nlcount <= nn) { 
    if (*rit == '\n') { 
      ++nlcount; 
    } 
    ++rit; 
  } 
  if (nlcount > nn) { 
    myfile.seekg(newpos + (buffer.rend() - rit) + 1); 
    break; 
  } 
  oldpos = newpos; 
} 

不要使用
getline()
,否则在处理长行时仍会导致缓冲行和崩溃。

要删除缓冲区依赖关系,一种方法是从末尾向后读取文件,以达到所需的行数。5在这里是硬编码的,但可以作为参数传递

std::ifstream fileReader("test.txt", std::ios_base::ate );
std::string currentLine;
long length;
int lines;
char c = '\0';

if( fileReader )
{
    length = fileReader.tellg();
    for(long i = length-2; i > 0; i-- )
    {
        fileReader.seekg(i);
        c = fileReader.get();
        if( c == '\r' || c == '\n' )
        {
            lines++;
            if (lines == 5)
                break;
        }
    }

    while(fileReader)
    {
        std::getline(fileReader, currentLine);
        std::cout << currentLine << std::endl;
    }

}
std::ifstream文件读取器(“test.txt”,std::ios\u base::ate);
std::字符串currentLine;
长度长;
内线;
字符c='\0';
if(文件阅读器)
{
length=fileReader.tellg();
对于(长i=length-2;i>0;i--)
{
fileReader.seekg(i);
c=fileReader.get();
如果(c='\r'| c=='\n')
{
行++;
如果(行==5)
打破
}
}
while(文件阅读器)
{
std::getline(文件阅读器,currentLine);

std::不能从描述它应该做什么开始(即使它很小,从写得不好的代码中找出它也不是一件愉快的事),而且看起来它有缺陷。
buffer[nn]
-不要使用可变长度数组。如果只显示最后5行,则不需要将所有文件内容存储在内存中。只存储最后5行,并在末尾显示它们。这是一种分配,不允许使用某些库类还是可以使用STL?我看不到任何明显的损坏re,虽然可能很难看。是时候停止盯着代码,启动一个实际的调试器了!@FernandoSilveira我已经在4GB文件上测试了它,它还可以。而且它没有任何用于缓冲的显式数组。@FernandoSilveira“4GB文件”不是“4GB行”。仔细阅读这个问题。你假设得太多了;)我的一些评论正在被删除(不是由我删除),因此我将继续并删除它们。如果输入中包含任何不属于crlf的
'\r'
,则此操作无效。而且它还会在很长的行上发生故障。所描述的问题与长行无关,因此使用
getline()没有问题
因为它不在问题中。你应该回答这个问题,而不是你的假设。我不是说你错了,我只是说不要确定并根据你的假设提出建议。此外,你没有提供你为什么说
getline()
将失败的原因,以及使用它的限制是什么。“阅读长行文件时出现问题”是一个非常普遍的问题,不应作为答案。
std::ifstream fileReader("test.txt", std::ios_base::ate );
std::string currentLine;
long length;
int lines;
char c = '\0';

if( fileReader )
{
    length = fileReader.tellg();
    for(long i = length-2; i > 0; i-- )
    {
        fileReader.seekg(i);
        c = fileReader.get();
        if( c == '\r' || c == '\n' )
        {
            lines++;
            if (lines == 5)
                break;
        }
    }

    while(fileReader)
    {
        std::getline(fileReader, currentLine);
        std::cout << currentLine << std::endl;
    }

}