【问题标题】:Loop on all lines of very large file C# [duplicate]在非常大的文件C#的所有行上循环[重复]
【发布时间】:2018-08-15 09:40:13
【问题描述】:

我想使用foreach循环一个非常大的文件(例如 10GB)的所有行

我目前正在像这样使用File.ReadLines

var lines = File.ReadLines(fileName);
foreach (var line in lines) {
  // Process line
}

但是如果文件大于 2MB,这会很慢,而且循环会很慢。

如何循环播放非常大的文件?

任何帮助将不胜感激。

谢谢!

【问题讨论】:

标签: c# foreach


【解决方案1】:

考虑到这一点,你做的方式是最好的方式

  • 您不想一次将整个文件读入 RAM
  • 您的行处理独立于之前的行

抱歉,从硬盘读取内容很慢。

改进可能来自其他来源:

  • 将文件存储在速度更快的设备(SSD?)上
  • 获取更多 RAM 以将文件读入内存以至少加快处理速度

【讨论】:

    【解决方案2】:

    首先你需要读取整个文件还是只读取文件的一部分。

    如果你只需要阅读文件的部分

    const int chunkSize = 1024; // read the file by chunks of 1KB
    using (var file = File.OpenRead("yourfile"))
    {
        int bytesRead;
        var buffer = new byte[chunkSize];
        while ((bytesRead = file.Read(buffer, 0 /* start offset */, buffer.Length)) > 0)
        {
            // TODO: Process bytesRead number of bytes from the buffer
            // not the entire buffer as the size of the buffer is 1KB
            // whereas the actual number of bytes that are read are 
            // stored in the bytesRead integer.
        }
    }
    

    如果需要将整个文件加载到内存中。

    重复使用此方法,而不是直接加载到内存中,因为您可以控制自己在做什么,并且可以随时停止该过程。

    或者你可以使用MemoryMappedFile https://msdn.microsoft.com/en-us/library/system.io.memorymappedfiles.memorymappedfile.aspx?f=255&MSPPError=-2147217396

    内存映射文件会给程序一个从内存访问的视图,但它只会第一次从磁盘加载。

    long offset = 0x10000000; // 256 megabytes
    long length = 0x20000000; // 512 megabytes
    
    // Create the memory-mapped file.
    using (var mmf = MemoryMappedFile.CreateFromFile(@"c:\ExtremelyLargeImage.data", FileMode.Open,"ImgA"))
    {
         // Create a random access view, from the 256th megabyte (the offset)
         // to the 768th megabyte (the offset plus length).
         using (var accessor = mmf.CreateViewAccessor(offset, length))
         {
             //Your process
         }
    }
    

    【讨论】:

    • 为什么你认为 OP 只需要文件的一部分?
    • 我打赌 OP 正在逐行读取和处理:\
    • 您的编辑忽略了 File.ReadLines 为您完成所有这些流式传输的事实。
    • 我仍然相信这种方法甚至可以将整个文件加载到内存中更好,因为您可以控制该过程并在需要时适当地显示消息
    • 我不明白这如何适用于这个问题。当然你可以这样做......并在此基础上编写大量代码甚至达到 OP 认为的给定......但这仍然没有提高速度。
    【解决方案3】:

    由于您必须循环的项目数量众多,因此循环总是很慢。我很确定这不是循环,而是您在每一条减慢它的行上所做的实际工作。一个有 10GB 行的文件实际上可能有数万亿行,除了最简单的任务之外的任何事情都需要很多时间。

    您总是可以尝试使作业线程化,以便不同的线程在不同的行上工作。这样至少你有更多的核心来解决这个问题。

    设置一个 for 循环并让它们以不同的量递增。

    另外,我不是 100%,但我认为你可以通过根据新行拆分将整个内容拆分为字符串数组,然后处理这些内容,因为所有内容都存储在内存中,因此速度会大大提高。

    string lines = "your huge text";
    string[] words = lines.Split('\n');
    foreach(string singleLine in lines)
    {
    
    }
    

    ** 基于 cmets 添加 ** 所以有很大的缺点,并且会占用大量的内存。至少原始文件使用的数量,但这解决了硬盘驱动器速度慢的问题,所有数据将直接读取到机器的 RAM 中,这将远远快于从硬盘驱动器中读取小块.

    这里还有一个问题是大约 20 亿行的限制,因为这是您可以拥有的数组中的最大条目数。

    【讨论】:

    • 所以...手动将 10GB 数据复制到代码中,从而产生 10GB 的内存字符串文字?听起来很有趣……
    • 你在猜吗?因为我认为你根本没有测试过这个。它不仅可能会更慢,还会浪费大约 20 GB 或更多的 RAM。
    • "10GB 行的文件实际上会有数万亿行..." -> 粘贴到数组。所以现在我们有一个 10gb 的字符串文字(编译器将如何处理它(实际上我很好奇)),现在我们有一个包含 10gb 条目的数组(我也很好奇它将如何处理)。
    • 这里的cmets:“你在猜吗?因为我认为你根本没有测试过这个”。当然我没有测试过这个。我没有得到报酬。这些只是我的想法。 OP 可以到处玩,看看什么是最快的
    • 我同意,从 RAM 读取比从 HDD 读取“快得多”,但是您的解决方案需要以慢速 HDD 的速度从慢速 HDD 读取到快速 RAM。这不是和我从硬盘中逐行读取文件一样吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-11
    • 1970-01-01
    相关资源
    最近更新 更多