在 C# 中读取非常大的文本文件的最快方法
Fastest way to read very large text file in C#
我有一个非常基本的问题。我有几个文本文件,每个文件的数据大小为几 GB。我有一个 C# WPF 应用程序,我用它来处理类似的数据文件,但远不及那个大小(现在可能大约 200-300mb)。我怎样才能有效地读取这些数据,然后在处理后将它写到别处,而不至于所有东西都冻结和崩溃?从本质上讲,从一个非常大的文件中读取的最佳方法是什么?对于我现在的小规模应用程序,我使用 System.IO.File.ReadAllLines
读取和 streamwriter
写入。我确信这两种方法对于如此大的文件来说不是最好的主意。我对 C# 没有太多经验,任何帮助将不胜感激!
如果您可以逐行执行此操作,那么答案很简单:
- 读一行。
- 处理行。
- 写下这行。
如果你想让它走得快一点,把它们放在三个 BlockingCollections
中,并指定一个上限,比如 10,这样一个较慢的步骤永远不会等待更快的步骤。如果可以输出到不同的物理光盘(如果输出到光盘)。
即使在被问及该过程是否逐行(两次)后,OP 仍更改了规则。
- 读取行以生成工作单元(从打开到关闭标签)。
- 处理工作单元。
- 写工作单元。
这可能是某种重叠转换。
https://msdn.microsoft.com/en-us/library/dd997372(v=vs.110).aspx
首先,您需要将目标文件分配为尽可能接近可估计的结果大小。在大多数情况下,超调可能比欠调更可取,您始终可以截断到给定长度,但增长可能需要非连续分配。如果预期过度增长,您可以将文件分配为 "sparse" 文件。
选择大于或等于 512 字节的任意(可能是二进制幂)块大小(测试以找到最佳性能)。
映射源文件的2个块。这是您的源缓冲区。
映射目标文件的 2 个块。这是您的目标缓冲区。
对块内的行进行操作。从源块读取,写入目标块。
转换块边界后,执行 "buffer swap" 将前一个完成的块换成下一个块。
有几种方法可以完成这些任务。
如果您愿意,您可以一次为操作分配更多块,但您需要应用 "triple buffering" 重叠操作策略才能使用。如果写入比读取慢得多,您甚至可以使用与三重缓冲相同的模式实现无限内存缓冲。
根据您的数据,您还可以将块分发到单独的线程,即使它是一个 "line based" 文件。
如果每一行都依赖于之前的数据,可能没有办法加速运行。如果不是,在执行操作之前索引文件中的行将允许多个工作线程,每个工作线程在独立的块上运行。
如果我需要详细说明什么,就说哪一部分。
我有一个非常基本的问题。我有几个文本文件,每个文件的数据大小为几 GB。我有一个 C# WPF 应用程序,我用它来处理类似的数据文件,但远不及那个大小(现在可能大约 200-300mb)。我怎样才能有效地读取这些数据,然后在处理后将它写到别处,而不至于所有东西都冻结和崩溃?从本质上讲,从一个非常大的文件中读取的最佳方法是什么?对于我现在的小规模应用程序,我使用 System.IO.File.ReadAllLines
读取和 streamwriter
写入。我确信这两种方法对于如此大的文件来说不是最好的主意。我对 C# 没有太多经验,任何帮助将不胜感激!
如果您可以逐行执行此操作,那么答案很简单:
- 读一行。
- 处理行。
- 写下这行。
如果你想让它走得快一点,把它们放在三个 BlockingCollections
中,并指定一个上限,比如 10,这样一个较慢的步骤永远不会等待更快的步骤。如果可以输出到不同的物理光盘(如果输出到光盘)。
即使在被问及该过程是否逐行(两次)后,OP 仍更改了规则。
- 读取行以生成工作单元(从打开到关闭标签)。
- 处理工作单元。
- 写工作单元。
这可能是某种重叠转换。
https://msdn.microsoft.com/en-us/library/dd997372(v=vs.110).aspx
首先,您需要将目标文件分配为尽可能接近可估计的结果大小。在大多数情况下,超调可能比欠调更可取,您始终可以截断到给定长度,但增长可能需要非连续分配。如果预期过度增长,您可以将文件分配为 "sparse" 文件。
选择大于或等于 512 字节的任意(可能是二进制幂)块大小(测试以找到最佳性能)。
映射源文件的2个块。这是您的源缓冲区。
映射目标文件的 2 个块。这是您的目标缓冲区。
对块内的行进行操作。从源块读取,写入目标块。
转换块边界后,执行 "buffer swap" 将前一个完成的块换成下一个块。
有几种方法可以完成这些任务。
如果您愿意,您可以一次为操作分配更多块,但您需要应用 "triple buffering" 重叠操作策略才能使用。如果写入比读取慢得多,您甚至可以使用与三重缓冲相同的模式实现无限内存缓冲。
根据您的数据,您还可以将块分发到单独的线程,即使它是一个 "line based" 文件。
如果每一行都依赖于之前的数据,可能没有办法加速运行。如果不是,在执行操作之前索引文件中的行将允许多个工作线程,每个工作线程在独立的块上运行。
如果我需要详细说明什么,就说哪一部分。