C# – 将大文件加载到WPF RichTextBox中?

我需要将一个~10MB范围的文本文件加载到WPF RichTextBox中,但我当前的代码正在冻结UI。 我尝试让后台工作人员进行加载,但这似乎也不能很好地工作。

这是我的加载代码。 有没有办法改善其表现? 谢谢。

//works well for small files only private void LoadTextDocument(string fileName, RichTextBox rtb) { System.IO.StreamReader objReader = new StreamReader(fileName); if (File.Exists(fileName)) { rtb.AppendText(objReader.ReadToEnd()); } else rtb.AppendText("ERROR: File not found!"); objReader.Close(); } //background worker version. doesnt work well private void LoadBigTextDocument(object sender, DoWorkEventArgs e) { BackgroundWorker worker = sender as BackgroundWorker; System.IO.StreamReader objReader = new StreamReader( ((string[])e.Argument)[0] ); StringBuilder sB = new StringBuilder("For performance reasons, only the first 1500 lines are displayed. If you need to view the entire output, use an external program.\n", 5000); int bigcount = 0; int count = 1; while (objReader.Peek() > -1) { sB.Append(objReader.ReadLine()).Append("\n"); count++; if (count % 100 == 0 && bigcount < 15) { worker.ReportProgress(bigcount, sB.ToString()); bigcount++; sB.Length = 0; } } objReader.Close(); e.Result = "Done"; } 

图形控件并不是为处理那种数据而设计的,只是因为它变得不可行。 即使控件可以处理大字符串,控件中可见的内容与整个文本相比也是如此之少,以至于滚动条实际上​​变得无用。 要在文本中找到特定的行,您必须将滑块移动到它可以指定的最近位置,然后一次滚动一行几分钟……

您应该重新考虑如何显示数据,以便您可以以实际可以使用的方式进行操作,而不是将用户提交给无用的用户。

我正在做一个非常相似的项目。

该项目需要加载一个大文本文件(最大大小约为120MB,但我们想要更高),然后在树中构建文本文件的轮廓。 单击树中的节点将用户滚动到文本文件的该部分。

在与很多人交谈之后,我认为最好的解决方案是创建一种“滑动窗口”查看器,您只需将用户一次可以看到的文本加载到rtb.Text中。

所以..说将整个文件加载到List中,但只将100行放入rtb.Text。 如果用户向上滚动,请删除底行并在顶部添加一行文本。 如果他们向下滚动删除顶行并在底部添加一行文本。 这个解决方案让我的表现相当不错。 (加载120MB文件50秒)

WPF RichTextBox控件使用Flow Document显示RTF,然后将Flow Document附加到RTB控件,而Windows Form RichTextBox控件直接显示Rich Text。 这就是WPF RTB超级慢的原因。 如果您对使用WinForm RTB没问题,只需将其托管在您的wpf应用程序中即可。 xaml:

          

C#代码

 private void LoadTextDocument(string fileName, RichTextBox rtb) { System.IO.StreamReader objReader = new StreamReader(fileName); if (File.Exists(fileName)) { rtb.AppendText(objReader.ReadToEnd()); } else rtb.AppendText("ERROR: File not found!"); objReader.Close(); } 

为什么不添加到字符串变量(或者甚至可能使用StringBuilder),然后在完成解析时将值分配给.Text属性?

我注意到使用RichTextboxes,当你添加更多“线”时,它开始变慢。 如果你可以在不附加’\ n’的情况下完成它,它将为你加速。 请记住每个’\ n’是RichTextbox的新段落对象块。

这是我加载10 MB文件的方法。 加载大约需要30秒。 我使用进度条对话框让我的用户知道加载需要时间。

 // Get Stream of the file fileReader = new StreamReader(File.Open(this.FileName, FileMode.Open)); FileInfo fileInfo = new FileInfo(this.FileName); long bytesRead = 0; // Change the 75 for performance. Find a number that suits your application best int bufferLength = 1024 * 75; while (!fileReader.EndOfStream) { double completePercent = ((double)bytesRead / (double)fileInfo.Length); // I am using my own Progress Bar Dialog I left in here to show an example this.ProgressBar.UpdateProgressBar(completePercent); int readLength = bufferLength; if ((fileInfo.Length - bytesRead) < readLength) { // There is less in the file than the lenght I am going to read so change it to the // smaller value readLength = (int)(fileInfo.Length - bytesRead); } char[] buffer = new char[readLength]; // GEt the next chunk of the file bytesRead += (long)(fileReader.Read(buffer, 0, readLength)); // This will help the file load much faster string currentLine = new string(buffer).Replace("\n", string.Empty); // Load in background this.Dispatcher.BeginInvoke(new Action(() => { TextRange range = new TextRange(textBox.Document.ContentEnd, textBox.Document.ContentEnd); range.Text = currentLine; }), DispatcherPriority.Normal); } 

你可以试试这个对我有用。

 private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) { // Create new StreamReader StreamReader sr = new StreamReader(openFileDialog1.FileName, Encoding.Default); // Get all text from the file string str = sr.ReadToEnd(); // Close the StreamReader sr.Close(); // Show the text in the rich textbox rtbMain backgroundWorker1.ReportProgress(1, str); } private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e) { // richTextBox1.Text = e.ProgressPercentage.ToString() + " " + e.UserState.ToString(); richTextBox1.Text = e.UserState.ToString(); } 

您是否考虑过尝试将应用程序设置为multithreading?

您需要立即查看多少文本文件? 您可能希望在.NET中或在您的情况下查看延迟加载C#

我没有提高加载的性能,但我用它来异步加载我的richtextbox。 我希望这可以帮到你。

XAML:

  

帮手:

 public class RichTextBoxHelper { private static readonly ILog m_Logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); public static readonly DependencyProperty BindableSourceProperty = DependencyProperty.RegisterAttached("BindableSource", typeof(string), typeof(RichTextBoxHelper), new UIPropertyMetadata(null, BindableSourcePropertyChanged)); public static string GetBindableSource(DependencyObject obj) { return (string)obj.GetValue(BindableSourceProperty); } public static void SetBindableSource(DependencyObject obj, string value) { obj.SetValue(BindableSourceProperty, value); } public static void BindableSourcePropertyChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) { var thread = new Thread( () => { try { var rtfBox = o as RichTextBox; var filename = e.NewValue as string; if (rtfBox != null && !string.IsNullOrEmpty(filename)) { System.Windows.Application.Current.Dispatcher.Invoke( System.Windows.Threading.DispatcherPriority.Background, (Action)delegate() { rtfBox.Selection.Load(new FileStream(filename, FileMode.Open), DataFormats.Rtf); }); } } catch (Exception exception) { m_Logger.Error("RichTextBoxHelper ERROR : " + exception.Message, exception); } }); thread.Start(); } }