程序应该显示文件的最后 5 行,但它不适用于大文件
Posted
技术标签:
【中文标题】程序应该显示文件的最后 5 行,但它不适用于大文件【英文标题】:the program should display the last 5 lines of the file, but it does not work with large files 【发布时间】:2019-11-13 10:29:49 【问题描述】:我写了一个程序,应该打印文件的最后 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;
【问题讨论】:
从描述它应该做什么开始(即使它很小,从写得不好的代码中弄清楚这一点也很不愉快)。看起来它有问题。buffer[nn];
- 不要使用变长数组。
如果只显示最后 5 行,则不需要将所有文件内容存储在内存中。只存储最后读取的 5 行并在最后显示。
这是一些作业,不允许您使用某些库类还是可以使用 STL?
我没有看到任何明显的损坏,尽管它可能很丑。是时候停止盯着代码并启动实际的调试器了!
【参考方案1】:
问题一定是那个 4GB 文件中的大行。您的解决方案缓冲(然后删除)每一行,并且至少其中一行可能太长而无法在您正在运行的机器中进行缓冲,从而使您的程序崩溃。
您应该从末尾开始读取文件,计算换行符的数量,并在达到nn + 1
的计数时停止并输出其余部分。当您需要处理大行时,缓冲最后的 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()
,否则在处理长行时,您仍然会缓冲行并崩溃。
【讨论】:
所描述的问题与长线无关,所以使用getline()
没有问题
因为它不在问题中。你应该回答这个问题而不是你的假设。
我不是说你错了,我只是说不要确定并根据你的假设提出建议。此外,您没有提供为什么您说getline()
会失败以及使用它的限制是什么。 “读取长行文件的问题”非常笼统,不应用作答案。【参考方案2】:
要消除缓冲区依赖性,一种方法是从末尾向后读取文件以达到所需的行数。 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;
【讨论】:
@FernandoSilveira 我已经在 4GB 文件上对其进行了测试,结果还可以。它也没有任何明确的缓冲数组。 @FernandoSilveira “4GB 文件”而不是“4GB 线路”。仔细阅读问题。 你假设太多了;) 我的一些 cmets 正在被移除(不是我自己),所以我会继续将它们全部移除。 如果输入包含不属于 crlf 的任何'\r'
,则此方法不起作用。而且它也会分解成很长的行。以上是关于程序应该显示文件的最后 5 行,但它不适用于大文件的主要内容,如果未能解决你的问题,请参考以下文章
来自画廊工作的文件选择器,但它不适用于 android webview 中的相机