逐行解析CMemFile中的文本

时间:2011-05-31 12:04:38

标签: c++ windows mfc

我有一个巨大的文本文件加载到CMemFile对象中,并希望逐行解析(由换行符分隔)。
最初它是磁盘上的zip文件,我将其解压缩到内存中来解析它,因此是CMemFile。

逐行读取的一种工作方式是(m_file是指向CMemFile的智能指针):

    CArchive archive(m_file.get(), CArchive::load);

    CString line;

    while(archive.ReadString(line))
    {
        ProcessLine(string(line));
    }

由于花了很多时间,我试着编写自己的例程:

    const UINT READSIZE = 1024;
    const char NEWLINE = '\n';
    char readBuffer[READSIZE];
    UINT bytesRead = 0;
    char *posNewline = NULL;

    const char* itEnd = readBuffer + READSIZE;
    ULONGLONG currentPosition = 0;
    ULONGLONG newlinePositionInBuffer = 0;

    do
    {
        currentPosition = m_file->GetPosition();

        bytesRead = m_file->Read(&readBuffer, READSIZE);        

        if(bytesRead == 0) break; // EOF

        posNewline = std::find(readBuffer, readBuffer + bytesRead, NEWLINE);

        if(posNewline != itEnd)
        {
            // found newline
            ProcessLine(string(readBuffer, posNewline));
            newlinePositionInBuffer = posNewline - readBuffer + 1; // +1 to skip \r
            m_file->Seek(currentPosition + newlinePositionInBuffer, CFile::begin);
        }
    } while(true);

测量性能表明两种方法大约需要同时...

你能想到任何性能改进或更快的解析方法吗?

感谢您的任何建议

4 个答案:

答案 0 :(得分:2)

可能有用的一些注释和评论:

  • 分析是确保知道代码正在做什么以及需要多长时间的唯一方法。通常,代码本身的瓶颈并不明显。一种基本方法是单独对加载,解压缩和解析进行计时。
  • 从磁盘实际加载文件,在你的情况下是解压缩,实际上可能比解析花费更多的时间,特别是如果你的ProcessFile()函数是一个nop。如果你的解析只花费总时间的1%,那么你就不会从尝试优化1%中获得太多。这是您的代码会告诉您的分析。
  • 优化加载/解析算法的一般方法是查看特定字节的读取/解析次数。最小且可能最快的算法必须只读取和解析每个字节一次。查看您的算法,每个字节似乎被复制了六次,并且可能会解析相似的数字。减少这些数字可能有助于缩短整体算法时间,尽管相对增益可能不是很大。

答案 1 :(得分:1)

使用分析器显示,在这行代码中浪费了75%的处理时间:

 ProcessLine(string(readBuffer, posNewline));

主要是临时字符串的创建造成了很大的开销(很多分配)。 ProcessLine函数本身不包含代码。通过更改声明:

void ProcessLine(const std::string &);

为:

inline void ProcessLine(const char*, const char*);

使用的处理时间减少了五倍。

答案 2 :(得分:0)

您可以在单独的线程中运行解压缩和解析。每次解压缩产生一些数据时,您应该使用消息机制将其传递给解析线程进行解析。

这允许两者并行运行,并且还因为您使用块而不是整个解压缩文件(这将导致更少的页面错误和交换到虚拟内存)而导致更小的内存开销。

答案 3 :(得分:0)

我认为你的问题可能是因为你读得太多并且正在寻找新的一线。

如果您提交的是

   foo
   bar
   etc

说一行平均10个字节。您将阅读10行...并再次阅读9行。