【问题标题】:Need help managing large files需要帮助管理大文件
【发布时间】:2012-01-01 19:23:24
【问题描述】:

我想读取 4GB 文件并通过更改某些字段来创建它的副本。我的首要任务是时间效率,即处理速度应该很快。
我想将它加载到内存中,以便读/写操作变得更快。我应该使用堆吗?或者我应该尝试其他的东西,比如内存映射文件?或任何其他出路?

首先感谢大家的贡献……让我重新提出我的问题……给你……
我必须从用户那里得到一个文件,这个文件大约 3-4GB 大。它包含记录,每条记录都有一些字段,其中包含一些敏感数据,我需要对其进行搜索和加密,直到 EOF..
如果我使用 FILE I/O 执行搜索和加密,它将永远……作为它的批处理……所以当我在 64 位操作系统上工作时,我可以在堆上创建一个 4GB 的数组,加载整个文件并执行操作。此本地副本将提供比 FILE IO 更好的性能...
我正在考虑内存映射文件,因为它将消除对数组(本地副本)的需求并且操作速度也很好,但是我不熟悉它,所以询问上述场景是否可取...... !!
我也在考虑考虑使用 MATLAB ......你也可以建议你是否有更好的出路.. thnx ...

【问题讨论】:

    标签: c++ c memory-management file-io linux-kernel


    【解决方案1】:

    我的猜测是使用内存映射方法,但您应该真正尝试一下并衡量什么可以为您提供最佳性能。从简单直接的实现开始,如果还不够好,请尝试对其进行优化。

    【讨论】:

    • 我支持内存映射方法。除了某些访问模式外,它是最简单和最快的一种。应该记住,要成功映射 整个 4 GiB 文件,机器上的地址大小需要 >32 位。如有必要,部分映射将解决此类限制。
    • 对专业人士来说是正确的,但问题似乎是初学者的问题。内存映射 I/O 需要一些关于底层系统架构的知识。
    • @frunsi 不,它不需要了解底层系统架构。
    • @VJovic:嗯,Linux 在 mmap 的 IO 方面绝对出色。让我们忽略其他架构:但是,细节,那些血腥的细节。对于我们的问题,我们真的应该从基础开始。
    【解决方案2】:

    解决方案很简单,但需要您提供有关给定文件格式的详细信息的更多信息。

    但是,一些通用解决方案的伪代码(纯 C,需要时要求 C++ 实现):

    #define BUFSIZE 4096 // 4k, try larger or smaller values to improve performance...
    
    int process_file( const char* filename ) {
      char buffer[BUFSIZE];
      size_t nread;
      FILE* fp;
      if( (fp=fopen(filename,"rb"))==NULL ) return 1;
      while( (nread=fread(buffer,1,BUFSIZE,fp))>=0 ) {
        if( nread==0 ) break; // EOF
        process_file_buffer( buffer, nread );
      }
      fclose(fp);
      return nread>=0 ? 0 : 2; // 0==success, 2==read error, check "errno"!
    }
    
    void process_file_buffer( const char* buffer, size_t size ) {
      // process, and write result to target file
    }
    

    编辑

    关于您的内存管理问题的疑问:这在很大程度上取决于您的实际代码和您的实际要求。在我的示例代码中,只有一个缓冲区自动分配在堆栈上,对于该用例来说完全足够了。

    但是,如果您有特殊要求,请明确询问!

    另一个编辑:

    这段代码很扎实,为更多内容提供了完美的基础。但是:如果您遇到性能问题,那么您真的必须运行分析器(或编写和您自己的分析代码)。

    为什么?

    你可能怀疑这个代码是瓶颈,但我敢打赌它不会是;)别忘了,你还必须向 DISK 写一些东西,别忘了你必须通过任何文件的单个字节通过内存 - 并从那里通过 CPU 寄存器 - 来处理它(这是您的实际要求之一......)。

    SO:暂时不要介意内存映射 IO。首先,您必须考虑其他任何事情;)

    你可能不喜欢听到这个。但这只是你最初的情况。

    而且,在您开始考虑内存管理之前,您应该开始考虑您的实际 I..O.. 需求。

    另一个编辑:

    KISS - 保持简单,愚蠢;-)

    【讨论】:

    • 您正在分配一个 BUFSIZE 指针数组,而我认为您想要字符?你可能想在完成后关闭文件。
    • +1 加载文件的一部分并对其进行处理,使得处理与加载并行成为可能。在许多情况下将是最有效的解决方案。
    • @daramarak:是的,毕竟这段代码不会让任何有类似任务经验的人感到惊讶。但它有效,而且非常坚固。顺便说一句..我应该添加一些东西...
    • @daramarak 不,这是更糟糕的建议,而且不正确。
    • @VJovic 对我来说看起来像是一种务实的方法。特别是早些时候,当对数据的处理一无所知时,这是一个合理的解决方案。如果不正确,请您指出代码错误的方式,以便可以更正。仅仅说解决方案更糟糕和不正确是没有建设性的。
    【解决方案3】:

    根据您对问题的描述,我不确定您是否可以避免 I/O 性能不佳。如果您必须扫描 4gb 的数据以获取所需的记录,然后再次将整个文件写出,我怀疑如果您使用普通文件 I/O 或 mmap 会很重要,因为瓶颈将读取数据关闭磁盘。在这两种情况下,内核都会尝试缓存文件中经常访问的部分,以便快速重新读取。

    听起来您希望文件系统提供某种写时复制支持,但这高度依赖于文件系统功能(如果它们存在的话)。

    您可以尝试将 mmap 与 MAP_PRIVATE 一起使用。您将首先将源文件映射到内存中。所做的任何更改都将仅保存在内存中(MAP_PRIVATE),但文件的任何未触及部分都将从原始文件备份(如果您不触摸它,则会减少内存压力)。然后,您必须使用通过映射内存的普通文件 I/O 来写出新文件。但是我怀疑内核是否足够聪明,可以发现任何不需要的复制。

    正如其他人指出的那样,对于这种大小的文件,一次映射整个文件需要 64 位架构。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-10
      • 2019-03-26
      • 2018-06-12
      • 1970-01-01
      • 1970-01-01
      • 2017-03-21
      相关资源
      最近更新 更多