程序应该显示文件的最后5行,但它不适用于大文件
the program should display the last 5 lines of the file, but it does not work with large files
我写了一个程序,应该打印文件的最后5行,但老师创建了一个行为4GB的文件,程序坏了。如何重写程序,使其能够处理非常大的文件
一个可能的解决方案是逐个字符地读取文件,但我不知道如何做到
这是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 newlinesn";
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()
,否则在处理长的行时仍然会缓冲行并崩溃。
要删除缓冲区依赖关系,一种方法是从文件末尾向后读取文件,以达到所需的行数。5在这里是硬编码的,但您可以将其作为参数传递。
std::ifstream fileReader("test.txt", std::ios_base::ate );
std::string currentLine;
long length;
int lines;
char c = ' ';
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;
}
}
相关文章:
- FLTK 2.0构建和演示,适用于VS2019的2011年左右的代码库
- "string.h"在构建适用于iOS的qt应用程序中找不到消息
- 为什么 std::erase(std::erase_if) 不是适用于<algorithm>任何容器的模板?
- 为什么这适用于 G++ 而不是 CLANG?
- 为什么不区分大小写适用于 std::unordered_set的 std::hash 函数?
- 声明适用于 auto,但不能显式声明类型?
- 什么是通用运行时组件 #ifdef 适用于Windows(UWP)而不是iOS
- Windows 上的 Cmake 不添加共享库路径(适用于 linux)
- Typedef适用于结构,但不适用于枚举,仅适用于C++
- 为什么函数模板不理解 NULL,但适用于 nullptr
- 链接器读取库,但在其中找不到符号?未解析的外部符号,但仅适用于 Win32 而不是 x64
- Netbeans 8.1(适用于 C/C++)找不到我的编译器(gcc-6.0.0 开发版本)
- random_shuffle() 适用于 Windows,但不能在 Linux 上编译
- C++指针到方法模板推导在面向 x86 时不编译,但适用于 x64
- 不在异常中嵌入std::字符串的规则是否仍然适用于move构造函数
- 移动文件夹Windows c++:适用于Vista及以上版本,不包括XP
- 适用于Android的Qt找不到任何兼容的设备答案找到但不知道如何
- 在Windows 7上不起作用,但它适用于Windows 8 dll。
- 可变参数模板转换为 std::function<R(ARGS...)>适用于 GCC 而不是 MSVC2013,为什么?
- C++11 cmath 函数不在 std 命名空间中,适用于 android NDK w/gcc-4.8 或 clang