C++ 程序应显示文件的最后5行,但不能处理大文件
我写了一个程序,应该打印文件的最后5行,但是老师创建了一个4 GB的文件,程序坏了。如何重写程序,使其能够处理非常大的文件 一个可能的解决方案是逐字符读取文件,但我不知道如何执行 这是c++程序代码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
#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;j cout问题一定是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;
}
}