我编写了一个程序,应该打印文件的最后 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;
}
}
最佳答案
问题肯定出在 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;
}
如果nlcount
等于nn + 1
,这会将输入流指向您只需要输出其余部分的确切位置嗯>。我建议您不使用缓冲行输出它,而是使用固定大小的缓冲区:
while (myfile.peek() != EOF) {
myfile.read(buffer.data(), buffer.size());
cout.write(buffer.data(), myfile.gcount());
}
不要使用getline()
,否则在处理长行时您仍然会缓冲行并崩溃。
关于c++ - 程序应该显示文件的最后 5 行,但不适用于大文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58835047/