用C ++高效读取大型电子表格文件

时间:2010-06-24 14:42:27

标签: c++ csv spreadsheet

我通常使用csv parser中描述的方法来阅读电子表格文件。但是,当读取具有大约40列和250K行数据的64MB文件时,大约需要4分钟。在原始方法中,CSVRow类用于逐行读取文件,私有向量用于存储行中的所有数据。

有几点需要注意:

  • 我确实保留了足够的载体容量,但没什么用处。
  • 我还需要在读取每一行时创建某个类的实例,但即使代码只读入数据而不创建任何实例,也需要很长时间。
  • 该文件以制表符分隔,而不是以逗号分隔,但我认为不重要。

由于该文件中的某些列不是有用的数据,因此我将方法更改为具有私有字符串成员来存储所有数据,然后找到第(n-1)个和第n个分隔符的位置以获得有用的数据数据(当然有很多有用的专栏)。通过这样做,我避免了一些push_back操作,并将时间缩短到2分多钟。但是,这对我来说似乎太长了。

以下是我的问题:

  1. 有没有办法阅读这样的 电子表格文件更有效率?

  2. 我应该通过缓冲区读取文件     而不是逐行?如果是这样,怎么样     通过缓冲区读取并使用csvrow     类

  3. 我没有尝试过boost tokenizer,是的 那效率更高吗?
  4. 感谢您的帮助!

3 个答案:

答案 0 :(得分:2)

看起来你被IO瓶颈了。不是逐行读取文件,而是以8 MB的块读取它。解析块读取的记录,并确定块的结尾是否是部分记录。如果是,则从块中复制最后一条记录的部分并将其添加到下一个块。重复,直到文件全部被读取。这样,对于64 MB文件,您只需要发出8个IO请求。您可以尝试使用块大小来确定与内存使用情况相比最佳性能。

答案 1 :(得分:0)

如果将整个数据读入可接受的内存(显然是这样),那么我会这样做:

  1. 将整个文件读入std :: vector
  2. 填充矢量>其中包含所有换行符的起始位置和单元格数据。这些位置表示每个单元格的开始/结束
  3. 一些代码草图来展示这个想法:

    vector<vector<vector<char>::size_Type> > rows;
    for ( vector<char>::size_type i = 0; i < data.size(); ++i ) {
        vector<vector<char>::size_type> currentRow;
        currentRow.push_back( i );
        while ( data[i] != '\n' ) {
            if ( data[i] == ',' ) { // XXX consider comma at end of line
                currentRow.push_back( i );
            }
        }
        rows.push_back( currentRow );  
    }
    // XXX consider files which don't end in a newline
    

    因此,您知道所有换行符和所有逗号的位置,并且您可以将完整的CSV日期作为一个连续的内存块。因此,您可以轻松提取如下的单元格文本:

    // XXX error checking omitted for simplicity
    string getCellText( int row, int col )
    {
         // XXX Needs handling for last cell of a line
         const vector<char>::size_type start = rows[row][col];
         const vector<char>::size_type end = rows[row][col + 1]; 
         return string(data[start], data[end]);
    }
    

答案 2 :(得分:0)

This article应该会有所帮助。

简而言之:
1.使用内存映射文件或以4kbyte块读取文件以访问数据。内存映射文件会更快 2.尽量避免在解析循环中使用push_back,std :: string操作(如+)和类似的stl例程。它们很好,但它们都使用动态分配的内存,动态内存分配很慢。任何经常动态分配的东西都会使你的程序变慢。尝试在解析之前预先分配所有缓冲区。计算所有令牌以便为它们预分配记忆应该不难 3.使用分析器确定导致减速的原因 4.您可能希望尽量避免使用iostream的&lt;&lt;和&gt;&gt;运算符,并自己解析文件。

通常,高效的C / C ++解析器实现应该能够在3秒内解析20兆字节的大文本文件。