找到某个令牌时,是否有更快的方法来拆分文本文件?

时间:2014-09-11 04:38:26

标签: c++ text split

我有一个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;

分隔的唯一记录

1 个答案:

答案 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 ......