用带缓冲的c++逐行读取巨大的文本文件
read huge text file line by line in C++ with buffering
我需要在c++中一行一行地从光盘读取巨大的35G文件。目前我是这样做的:
ifstream infile("myfile.txt");
string line;
while (true) {
if (!getline(infile, line)) break;
long linepos = infile.tellg();
process(line,linepos);
}
但是它给了我大约2MB/s的性能,尽管文件管理器以100Mb/s的速度复制文件。我猜getline()
没有正确地做缓冲。请提出一种逐行缓冲的阅读方法。
UPD: process()不是瓶颈,没有process()的代码工作速度相同。
使用标准IO流,您将无法获得接近线路速度的任何地方。不管有没有缓冲,几乎任何解析都会降低你的速度。我在由两个int和一个double组成的数据文件上做了实验(Ivy Bridge芯片,SSD):
- 各种组合的IO流:~ 10mb/s。纯解析(
f >> i1 >> i2 >> d
)比getline
解析字符串然后sstringstream
解析更快。 - C文件操作,如
fscanf
得到大约40 MB/s。 -
getline
无解析:180 MB/s -
fread
: 500- 800mb/s(取决于文件是否被OS缓存)。
I/O不是瓶颈,解析才是。换句话说,您的process
可能是您的慢点。
-
fread
大块(一次一个这样的任务) - 重新排列块,这样一行不会在块之间分裂(一次一个这样的任务)
- 解析块(许多这样的任务)
我可以有无限的解析任务,因为我的数据是无序的。如果你的不是,那么这对你来说可能不值得。这种方法使我在4核IvyBridge芯片上获得大约100 MB/s的速度。
我已经从我的java项目中翻译了我自己的缓冲代码,它做了我需要的。我必须用定义来克服m$ VC 2010编译器提示的问题,它总是在大文件上给出错误的负值。该算法给出了理想的速度~100MB/s,尽管它做了一些无用的新[]。
void readFileFast(ifstream &file, void(*lineHandler)(char*str, int length, __int64 absPos)){
int BUF_SIZE = 40000;
file.seekg(0,ios::end);
ifstream::pos_type p = file.tellg();
#ifdef WIN32
__int64 fileSize = *(__int64*)(((char*)&p) +8);
#else
__int64 fileSize = p;
#endif
file.seekg(0,ios::beg);
BUF_SIZE = min(BUF_SIZE, fileSize);
char* buf = new char[BUF_SIZE];
int bufLength = BUF_SIZE;
file.read(buf, bufLength);
int strEnd = -1;
int strStart;
__int64 bufPosInFile = 0;
while (bufLength > 0) {
int i = strEnd + 1;
strStart = strEnd;
strEnd = -1;
for (; i < bufLength && i + bufPosInFile < fileSize; i++) {
if (buf[i] == 'n') {
strEnd = i;
break;
}
}
if (strEnd == -1) { // scroll buffer
if (strStart == -1) {
lineHandler(buf + strStart + 1, bufLength, bufPosInFile + strStart + 1);
bufPosInFile += bufLength;
bufLength = min(bufLength, fileSize - bufPosInFile);
delete[]buf;
buf = new char[bufLength];
file.read(buf, bufLength);
} else {
int movedLength = bufLength - strStart - 1;
memmove(buf,buf+strStart+1,movedLength);
bufPosInFile += strStart + 1;
int readSize = min(bufLength - movedLength, fileSize - bufPosInFile - movedLength);
if (readSize != 0)
file.read(buf + movedLength, readSize);
if (movedLength + readSize < bufLength) {
char *tmpbuf = new char[movedLength + readSize];
memmove(tmpbuf,buf,movedLength+readSize);
delete[]buf;
buf = tmpbuf;
bufLength = movedLength + readSize;
}
strEnd = -1;
}
} else {
lineHandler(buf+ strStart + 1, strEnd - strStart, bufPosInFile + strStart + 1);
}
}
lineHandler(0, 0, 0);//eof
}
void lineHandler(char*buf, int l, __int64 pos){
if(buf==0) return;
string s = string(buf, l);
printf(s.c_str());
}
void loadFile(){
ifstream infile("file");
readFileFast(infile,lineHandler);
}
使用行解析器或编写相同的内容。下面是sourceforge http://tclap.sourceforge.net/中的一个示例,必要时放入缓冲区。
相关文章:
- 文本文件中的单词链表
- 从命令行c++发送文本文件名
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 2D数组来自文本输入,中间有空格
- 如何将内容数组写入文本文件?
- 无法通过空白将文本文件行分隔为矢量
- 我正在使用嵌套的while循环来解析具有多行的文本文件,但由于某种原因,它只通过第一行,我不知道为什么
- C++将文本文件中的数据读取到结构数组中
- 在指针的帮助下,文本文件中单词的频率
- 将字符指针十六进制转换为字符串并保存在文本文件C++中
- 将值从二维数组输出到文本文件
- 在linux上调试巨大的C++项目
- 如何在c++中从文本文件中逐行读取整数
- 如何在一个巨大的文本文件中对整数进行排序
- SFML文本在小视图中显得巨大
- 用带缓冲的c++逐行读取巨大的文本文件
- 巨大的.cpp文件比从文本文件读取更好
- 将巨大的2D矢量写入文本文件太慢,如何提高性能
- 在c++中将一个巨大的文本文件(2Gb以上)分成2个块
- 在c++中替换,添加和删除巨大文本文件中的行