我有一个7GB的文本文件,由多行记录组成,这些记录用一行只包含令牌" $$$$"。
我写了一个方法来分解它,一次解析一行,测试令牌,并相应地拆分。我们的想法是以循环方式将每个多行记录写入不同的输出文件。我的代码如下:
// Open all temp files for reading
int nThreads = threadData.size();
std::vector<ofstream*> ostrms(nThreads);
for (int i = 0; i < nThreads; ++i)
{
ostrms[i] = new ofstream(threadData[i].InFileName);
if (! ostrms[i]->is_open() )
return(false);
}
// parse mol records into temp files in round-robin fashion
std::vector<std::string> molRecord;
std::string line;
const std::string MOL_END_OF_RECORD = "$$$$";
int curOutfileNo = 0;
while( ! strm.eof() )
{
std::getline(strm,line);
if (line.find(MOL_END_OF_RECORD) != std::string::npos)
{
for (int i = 0; i < molRecord.size(); ++i)
*(ostrms[curOutfileNo]) << molRecord[i] << "\n";
(*ostrms[curOutfileNo]) << line << "\n";
curOutfileNo = (curOutfileNo+1) % nThreads;
molRecord.clear();
}
else
molRecord.push_back(line);
}
for (int i = 0; i < nThreads; ++i)
delete ostrms[i];
慢慢地运行非常(几分钟)。有更快的方法吗?
7GB文本文件包含245,634,858行和466537个由&#34; $$$$&#34;
分隔的唯一记录答案 0 :(得分:1)
如果您完全确定分割线包含完全 $$$$
而没有任何前缀或后缀字符(例如空格),则可以替换
if (line.find(MOL_END_OF_RECORD) != std::string::npos)
与
if (line == std::string(MOL_END_OF_RECORD))
但我不认为这很重要。
如果花一天时间来改进编码是值得的(我相信它不是),并假设一个Linux系统,你可以谨慎使用像read(2)这样的低级系统调用的聪明组合一个至少64千字节的大缓冲区,{兆数范围mmap(2),posix_fadvise(2),readahead(2)(在一个单独的线程中),...
如果您多次访问相同的文件(具有常量内容),您可以考虑对其进行预处理(或预先消化),例如填写一些GDBM索引文件,或某些Sqlite(或其他)&#34;数据库&#34;,并让您的真实应用程序使用这些。你也可以简单地计算一些&#34; index&#34;包含每个$$$$
分隔符的偏移量的文件。
正如我评论的那样,你应该考虑像time(1)这样的实用程序花费的wc(1)作为执行时间的合理下限。我猜他们可以告诉你实际上(在你的特定系统上)程序是I / O绑定的。
BTW,如果你的机器超过例如在运行程序之前,您可以简单地wc yourhugefile
使用10 GB的RAM。 wc
进程将使用您的文件数据填充文件系统RAM缓存。见http://www.linuxatemyram.com/
我们无法提供更多帮助,除非您解释什么是大数据,多久更改一次,以及您的申请是什么......
您还可以购买更多内存和/或某些SSD ......