在c+中快速读取文本文件+; 我目前正在编写一个C++程序,其中包括阅读大量的文本文件。每行约有400.000行,在极端情况下,每行包含4000个或更多字符。为了进行测试,我使用ifstream和cplusplus.com提供的实现读取了其中一个文件。这花了大约60秒,太长了。现在我想知道,有没有一种简单的方法可以提高阅读速度
编辑: 我使用的代码大致如下:在c+中快速读取文本文件+; 我目前正在编写一个C++程序,其中包括阅读大量的文本文件。每行约有400.000行,在极端情况下,每行包含4000个或更多字符。为了进行测试,我使用ifstream和cplusplus.com提供的实现读取了其中一个文件。这花了大约60秒,太长了。现在我想知道,有没有一种简单的方法可以提高阅读速度,c++,performance,io,ifstream,C++,Performance,Io,Ifstream,编辑: 我使用的代码大致如下: string tmpString; ifstream txtFile(path); if(txtFile.is_open()) { while(txtFile.good()) { m_numLines++; getline(txtFile, tmpString); } txtFile.close(); } 编辑2:我读取的文件只有82 MB大。我主要是说它可以达到4000,因为我认为可能需要知道才能
string tmpString;
ifstream txtFile(path);
if(txtFile.is_open())
{
while(txtFile.good())
{
m_numLines++;
getline(txtFile, tmpString);
}
txtFile.close();
}
编辑2:我读取的文件只有82 MB大。我主要是说它可以达到4000,因为我认为可能需要知道才能进行缓冲
编辑3:谢谢大家的回答,但鉴于我的问题,似乎没有太多的改进空间。我必须使用readline,因为我想计算行数。将ifstream实例化为二进制文件也不会加快读取速度。我将尽可能多地将其并行化,这至少应该是可行的
编辑4:显然有些事情我可以做。非常感谢sehe在这方面投入了这么多时间,我非常感谢!=) 更新:确保检查初始答案下方的(令人惊讶的)更新
内存映射文件对我很有用1:
更新 通过查看GNU coreutils
wc
的源代码,我发现我可以从中挤出最后一点性能。令我惊讶的是,使用从wc
改编的以下(大大简化)代码运行的时间约占上述内存映射文件运行时间的84%:
static uintmax_t wc(char const *fname)
{
static const auto BUFFER_SIZE = 16*1024;
int fd = open(fname, O_RDONLY);
if(fd == -1)
handle_error("open");
/* Advise the kernel of our access pattern. */
posix_fadvise(fd, 0, 0, 1); // FDADVICE_SEQUENTIAL
char buf[BUFFER_SIZE + 1];
uintmax_t lines = 0;
while(size_t bytes_read = read(fd, buf, BUFFER_SIZE))
{
if(bytes_read == (size_t)-1)
handle_error("read failed");
if (!bytes_read)
break;
for(char *p = buf; (p = (char*) memchr(p, '\n', (buf + bytes_read) - p)); ++p)
++lines;
}
return lines;
}
1请参见此处的基准测试:4000*400000=1.6 GB如果硬盘驱动器不是SSD,则可能会获得约100 MB/s的顺序读取。仅在I/O中就需要16秒 由于您没有详细说明您使用的特定代码或您需要如何解析这些文件(您需要逐行读取它吗,系统是否有大量RAM?您可以将整个文件读入一个大的RAM缓冲区,然后解析它吗?),因此您几乎无法加快该过程 按顺序读取文件时,内存映射文件不会提供任何性能改进。也许手动解析大块新行而不是使用“getline”可以提供改进 学习后编辑(谢谢@sehe)。下面是我可能会使用的内存映射解决方案
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <errno.h>
int main() {
char* fName = "big.txt";
//
struct stat sb;
long cntr = 0;
int fd, lineLen;
char *data;
char *line;
// map the file
fd = open(fName, O_RDONLY);
fstat(fd, &sb);
//// int pageSize;
//// pageSize = getpagesize();
//// data = mmap((caddr_t)0, pageSize, PROT_READ, MAP_PRIVATE, fd, pageSize);
data = mmap((caddr_t)0, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
line = data;
// get lines
while(cntr < sb.st_size) {
lineLen = 0;
line = data;
// find the next line
while(*data != '\n' && cntr < sb.st_size) {
data++;
cntr++;
lineLen++;
}
/***** PROCESS LINE *****/
// ... processLine(line, lineLen);
}
return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
int main(){
char*fName=“big.txt”;
//
结构统计某人;
长cntr=0;
int fd,lineLen;
字符*数据;
字符*行;
//映射文件
fd=打开(仅fName,Ordu);
财政司司长(财务司司长及财务司司长);
////int页面大小;
////pageSize=getpagesize();
////数据=mmap((caddr t)0,页面大小,保护读取,映射私有,fd,页面大小);
数据=mmap((caddr t)0,标准尺寸,保护读取,地图私有,fd,0);
行=数据;
//排队
而(cntr
使用随机文件访问
或使用二进制模式
。对于sequential,这是一个很大的问题,但仍然取决于您正在阅读的内容。您必须同时读取所有文件吗?(例如,在应用程序开始时)
如果您这样做,请考虑并行化操作。
无论哪种方式,考虑使用二进制流,或unbffffd用于数据块。
< P>作为一个在竞争编程中有点背景的人,我可以告诉你:至少对于像整数解析这样简单的事情,C中的主要开销是锁定文件流(默认情况下是多线程处理)。改用unlocked_stdio
版本(fgetc_unlocked()
,fread_unlocked()
)。对于C++,一般的知识是使用<代码> STD::IOS:SycSyOffStdio(false)< /C> >但我不知道它是否和<代码> unLokKdStdio一样快。
这里是我的标准整数解析代码供参考。它比scanf快得多,正如我所说的,主要是因为没有锁定流。对我来说,它和我以前使用的最好的手工编码mmap或自定义缓冲版本一样快,没有疯狂的维护债务
int readint(void)
{
int n, c;
n = getchar_unlocked() - '0';
while ((c = getchar_unlocked()) > ' ')
n = 10*n + c-'0';
return n;
}
(注意:只有当任意两个整数之间正好有一个非数字字符时,此项才有效)
当然,如果可能的话,请避免内存分配…尼尔·柯克,很遗憾,我无法回复您的评论(声誉不够),但我对ifstream和stringstream进行了性能测试,逐行读取文本文件的性能完全相同
std::stringstream stream;
std::string line;
while(std::getline(stream, line)) {
}
对于一个106MB的文件,这需要1426ms
std::ifstream stream;
std::string line;
while(ifstream.good()) {
getline(stream, line);
}
在同一个文件上需要1433毫秒
以下代码速度更快:
const int MAX_LENGTH = 524288;
char* line = new char[MAX_LENGTH];
while (iStream.getline(line, MAX_LENGTH) && strlen(line) > 0) {
}
在同一个文件上需要884ms。
这只是有点棘手,因为您必须设置缓冲区的最大大小(即输入文件中每行的最大长度)。使用随机归档还是顺序归档?向我们展示您的代码或您正在阅读的内容?这在很大程度上取决于您在使用它时所做的操作。您可能希望将其拆分为多个部分,因为这对我来说似乎是一个内存瓶颈400000行*4000个特许权可能是160000000个字符,如果您的系统问题中一个字符是1字节,则可能是字节,您在实际代码中使用过stringstreams吗?它们的速度很慢。只需检查..+1的啤酒杯垫计算。不过SSD的速度可以达到约500Gb/s。内存映射可能更有效,这取决于使用场景。我需要逐行读取内存映射,因为它们不包含告诉我它们有多长的头。我可以把它们放在RAM缓冲区中,因为我可以在读取它们之后丢弃它们,但再一次,我认为ifstream就是这么做的。有没有办法告诉公关
std::ifstream stream;
std::string line;
while(ifstream.good()) {
getline(stream, line);
}
const int MAX_LENGTH = 524288;
char* line = new char[MAX_LENGTH];
while (iStream.getline(line, MAX_LENGTH) && strlen(line) > 0) {
}