在C# WinForms中绘制大型文本文件的最快方法

7
我有一个大文本文件(~100MB),我把它的每一行都存储在一个字符串列表中。 我的Winform偶尔需要显示其中的一部分,例如500,000行。
我尝试使用ListBox、RichTextBox和TextBox,但是绘制时间太长了。
例如,TextBox需要25秒才能显示500,000行, 而记事本立即打开这样大小的文本文件。
为此,最快的解决方案是什么?

你尝试使用正确的控件,但是错误的模式。请搜索“winforms virtual mode <control>”(例如,listbox)。 - Sinatr
2个回答

10

为什么不打开一个文件流,只读取前几行。当用户在文件中滚动并显示适当的行时,您可以使用 seek。关键是-将整个文件读入内存需要太长时间,所以不要这样做!

起始代码

以下是一小段不完整的代码片段,但它至少可以让你开始:

// estimate the average line length in bytes somehow:
int averageLineLengthBytes = 100;

// also need to store the current scroll location in "lines"
int currentScroll = 0;

using (var binaryReader = new StreamReader(new FileStream(fileName, FileAccess.Read)))
{
    if (binaryReader.BaseStream.CanSeek)
    {
        // seek the location to read:
        binaryReader.BaseStream.Seek(averageLineLengthBytes * currentScroll, SeekOrigin.Begin);

        // read the next few lines using this command
        binaryReader.ReadLine();
    }
    else
    {
        // revert to a slower implementation here!
    }
}

最大的难点在于估计滚动条的长度(文件中有多少行)。为此,您要么需要在用户滚动时更改滚动条 或者 您可以使用先前了解到的该文件中典型行的长度并根据总字节数估算长度。无论哪种方式,希望这有所帮助!

关于虚拟模式的说明

虚拟模式是使用ListBox或类似列表控件以按需加载项目的一种方法。当用户在控件内滚动时,控件将执行回调以基于索引检索项目。仅当您的数据符合以下条件时,这是可行的解决方案:

  • 您必须知道您希望呈现的数据项数量(事先)。如果您需要读取整个文件才能获取此总数,则无法使用虚拟模式!
  • 您必须能够根据该项的索引检索特定的数据项,而无需读取整个文件。
  • 您必须愿意按图标、小细节、详细信息或其他支持的格式呈现数据(或愿意进行大量额外工作来编写自定义列表视图)。

如果您无法满足这些条件,则虚拟模式将不会特别有帮助。我提供的使用seek的答案将在无论您是否可以执行这些操作时都可行。当然,如果您能够满足这些最低标准,那么请查找列表视图的虚拟模式,您应该会找到一些非常有用的信息!


为什么你不使用虚拟化,就像@Black From建议的那样(并且在WPF上也可用)? - Yishai Galatzer
1
@YishaiGalatzer,你所谓的“虚拟化”可以在ListView中使用,但前提是你事先知道确切的项目数量。它还仅限于特定的接口选项,而不允许以任何所需的方式显示数据。基于这两个事实,我认为这些并不是一个像通用文件阅读器那样好的解决方案,后者可以修改以满足OP的要求! - drew_w
@YishaiGalatzer 在答案中添加了一条注释,以解释虚拟模式的优缺点 :) - drew_w
因为像你上面建议的那样编写自己的虚拟化永远不会像你暗示的那么简单。根据最终产品所需的质量,他可能需要花费数天时间来调整和优化它以达到正确的效果。例如,滚动到末尾或顶部是常见的情况,可能会出现问题。所以你的想法没有错,但对于新手来说并不是一个解决方案。请注意,WPF控件没有你在答案中提到的限制。(谢谢!) - Yishai Galatzer
@YishaiGalatzer 已经注意到了。不幸的是,OP正在使用winforms。 - drew_w

1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接