【问题标题】:C++ Load text file, optimization [closed]C ++加载文本文件,优化[关闭]
【发布时间】:2011-12-30 11:21:32
【问题描述】:

我的源代码加载文本文件并将每一行分隔为单个项目(单词)。

如何进一步优化代码?测试空行(和其他结构)(在我看来)有点低效......

typedef std::vector < std::string >  TLines;
typedef std::vector < std::vector < std::string > > TItems;

TItems TFloadFile ( const char * file_name )
{
    //Load projection from file
    unsigned int lines = 0;
    char buffer[BUFF];
    FILE * file;
    TItems file_words;
    TLines file_lines;


    file = fopen ( file_name, "r" );

    if ( file != NULL )
    {
            for ( ; fgets ( buffer, BUFF, file ); )
            {
                    //Remove empty lines
                    bool empty_line = true;
                    for ( unsigned i = 0; i < strlen ( buffer ); i++ )
                    {
                            if ( !isspace ( ( unsigned char ) buffer[i] ) )
                            {
                                    empty_line = false;
                                    break;
                            }
                    }

                    if ( !empty_line )
                    {
                            file_lines.push_back ( buffer );
                            lines++;
                    }
            }


            file_words.resize ( lines + 1 );
            for ( unsigned int i = 0; i < lines; i++ )
            {
                    char * word = strtok ( const_cast<char *> ( file_lines[i].c_str() ), " \t,;\r\n" );
                    for ( int j = 0; word; j++, word = strtok ( 0, " \t;\r\n" ) )
                    {
                            file_words[i].push_back ( word );
                    }
            }

            fclose ( file );
    }

    return file_words;
}

感谢您的帮助...

【问题讨论】:

  • codereview.stackexchange.com 是解决这类问题的好论坛。
  • @保罗。感谢您的评论!
  • @All:感谢大家的意见、cmets、备注和代码示例……

标签: c++ file optimization load csv


【解决方案1】:

for ( unsigned i = 0; i &lt; strlen ( buffer ); i++ ) 行效率很低,因为您每次通过循环都在计算 buffer 的长度。但是,这可能会被编译器优化掉。

您将项目推送到您的std::vectors 上,而reserve() 没有任何空间。对于大文件,这将涉及大量开销,因为需要复制向量的内容才能调整它们的大小。我刚刚阅读了@Notinlist 的答案,其中已经谈到了std::vector::resize() 的低效率。

不是通过重复的fgets()调用将每一行读入一个向量,你能不能简单地确定文件中的字节数,动态分配一个char数组来保存它们,然后将字节转储到其中?然后,您可以解析这些单词并将它们存储在file_words 中。这将比您当前使用的方法更有效。

【讨论】:

  • “但是,这可能会被编译器优化掉。”编译器必须知道这个函数没有副作用,所以一般情况下这是不正确的(除非编译器进行链接时分析)
  • @Kamchatka:很公平,谢谢。更有理由将此值存储在变量中并引用它,而不是为每次传递重新计算它。
【解决方案2】:

在优化之前,您能否解释一下文件有多大、代码当前执行需要多长时间以及为什么您认为它还没有受到 IO 限制(即由于硬盘速度的原因)。你认为应该花多长时间?对文件中数据类型的一些想法也很好(例如平均行长度,空行的平均比例等)。

也就是说,将 remove-empty-line 循环与 word-tokenising 循环结合起来。然后您可以完全删除 TLines 并避免 std::string 构造和向量推回。我还没有检查过这段代码是否有效,但它应该足够接近给你这个想法。它还包括一个更高效的空行检测器:

if ( file != NULL )
{
    for ( ; fgets ( buffer, BUFF, file ); )
    {
        bool is_empty = true;
        for (char *c = buffer; *c != '\0'; c++)
        {
            if (!isspace(c))
            {
                is_empty = false;
                break;
            }
        }

        if (is_empty)
            continue;

        file_words.resize ( lines + 1 );
        char * word = strtok ( buffer, " \t,;\r\n" );
        for ( int j = 0; word; j++, word = strtok ( 0, " \t;\r\n" ) )
        {
                file_words[i].push_back ( word );
        }

        lines++;
    }

    fclose ( file );
}

【讨论】:

    【解决方案3】:

    一个人

    file_lines.push_back ( buffer );
    

    这是一条非常昂贵的线路。如果您不必使用矢量,请改用列表。完成这项工作后,可能会将您的列表转换为矢量。

    如果您绝对需要为此目的使用向量,那么您应该使用一些指数增量,例如:

    if(file_lines.size()<=lines){
        file_lines.resize((int)(lines * 1.3 + 1));
    }
    

    这样,您将有更少的 cpu 密集型 .resize() 操作,以最小的内存消耗开销为代价。

    【讨论】:

    • 为什么要调整大小 - 让矢量自己做 - 它会使用指数增量。
    • 你可以使用 .reserve() 代替 .resize()。
    • @Mark:不知道。参考?
    • @Notinlist:cplusplus.com/reference/stl/vector/reservestd::vector::reserve 是你的朋友 :) 编辑:哎呀,我看错了;我以为你没听说过reserve哈哈。我的错。
    • @Notinlist, Mark:我快速浏览了 C++03 标准,但找不到指数增量;我认为它可能是特定于实现的。就是说,我正在查看标准的vector 部分,而当时我可能应该查看allocator。无论如何,指数增量可能是最明智的选择。
    【解决方案4】:

    简化并转换为使用std::list 而不是std::vector

    typedef std::list< std::list< std::string > > TItems;
    
    TItems TFloadFile ( const char * file_name )
    {
        using namespace std;
        //Load projection from file
        ifstream file(file_name);
        TItems file_words;
        string line;
    
        for(getline(file,line); !file.fail() && !file.eof(); getline(file,line))
        {
            file_words.push_back(list<string>());
            list<string> &words(file_words.back());
    
            char *word = strtok((char*)line.c_str(), " \t,;\r\n" );
            for(; word; word=strtok( 0, " \t;\r\n" ))
            {
                words.push_back( word );
            }
            if(!words.size())
                file_words.pop_back();
        }
        return file_words;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-05-21
      • 1970-01-01
      • 2011-11-02
      相关资源
      最近更新 更多