0

I am creating a simple log parsing/reading application which becomes unresponsive when attempting to highlight a matched string (user defined input) and reports log file line string was found on within richTextBox1 for a large text file (1.5Mb or larger). Small text files work fine. Matched lines seem be displayed fine. The problem exists when attempting to highlight the matched string (when matched string is increasingly found).

//application has user select *.txt file and assign contents to string[] logContents, not streaming file.
//list of matched strings is made
//matched strings are displayed in richTextBox1

StringBuilder RTBtext = new StringBuilder(richTextBox1.Text);
if (displayMatched != null && displayMatched.Length > 0)
{
    //displays line of log file that matched the entered string
    for (int s = 0; s < displayMatched.Length; s++)
    {
        RTBtext.Append(displayMatched[s] + Environment.NewLine);
    }
}
richTextBox1.Text = RTBtext.ToString();

//newline \n added between matched line to increase readability

//Performance debugging shows "hot lines" with large CPU usage start here:
while (index < richTextBox1.Text.ToUpper().LastIndexOf(this.userInput1))
{
    richTextBox1.Find(this.userInput1, index, richTextBox1.Text.Length,RichTextBoxFinds.None);
    richTextBox1.SelectionColor = Color.White;
    richTextBox1.SelectionBackColor = Color.Blue;
    index = richTextBox1.Text.ToUpper().IndexOf(this.userInput1, index) + 1;
}

A similar style loop in another part of the program executes without issue. Do I have a problem with indexing? What is making the CPU work so hard? Performance debugging states System.Windows.Forms.RichTextBox.get_Text(); is the biggest bottleneck.

I have tried richTextBox1.SuspendLayout and ResumeLayout with no luck (also RTB1.SuspendPainting/ResumePainting).

Is it possible to only highlight, say, about 200 lines of matched strings at one time, then continue with richTextBox1.VScrollBar? If so, what is the best way to accomplish this?

Ry-
  • 218,210
  • 55
  • 464
  • 476
  • Is this really your working code? `richTextBox1.Find(this.userInput1, index, richTextBox1.Text.Length,RichTextBoxFinds.None);` returns an int which you don't use. It should not select text. – TaW Apr 28 '14 at 19:35
  • There are few things you can do to improve things off the top of my head. You could save the value of `richTextBox1.Text.ToUpper()`, and operate on that. Each time you call this method, it has to allocate a new string, as well as operate on each character. I would also cache the value of `richTextBox1.Text.ToUpper().LastIndexOf(this.userInput1)`, so you are not recalculating it each time you run through the loop. This should help minimize the amount of work the CPU has to do to recalculating values. – Velox Apr 28 '14 at 19:38
  • You must move the richTextBox.Text.ToUpper() expression out of the loop. And disable window updates while you are doing this, check [this answer](http://stackoverflow.com/a/3282911/17034). – Hans Passant Apr 28 '14 at 22:28

1 Answers1

1

In my experience, the RichTextBox does not play well with large amounts (megabytes+) of text loaded all at once.

My recommendation would be to directly process the text file at the invoking of search action, and store all match byte offsets and lengths into a separate hashset/dictionary.

Once you have a collection of line numbers and byte offsets, you can write text into the RichTextBox dynamically based on scroll position (aka infinite scroll). Every time you go to append new text to the RTB you check the byte positions in the hashset you made in the previous step. If you find a matching byte offset, you go ahead and mark-up your text at this time. Don't forget to remove text from the beginning of the RTB as you are adding it.

The way I would personally handle this application is that in addition to the above, have a separate summary view that contains matched line numbers and their contents. This way I can have a grep-like view of the document for all matches. When clicking on a summary view match item, it would scroll the RTB main view to that point in the document so that I can check entries around the one of concern.

I have used techniques like this before to handle gigabyte-sized log files.

  • Thank you @Bob, I would vote you up but I don't have enough reputation. I think i get your direction and logic; however, can you provide a chunk of code example regarding the scroll feature you described. – ordnerEnterprise Apr 30 '14 at 03:18