0

正如您将在此处看到的那样,我并不是真正的程序员,但如果能获得一些帮助以加快这个简单的搜索,我将不胜感激:

我有一些从 10 兆字节的文本文件中读取的代码,并将相关文本填充到文本框中,以帮助工作人员搜索零件号。它适用于后台工作人员,并且它填充文本框的速度非常慢,我想知道如何加快速度?可能是 String.Join 之类的东西?

 using (System.IO.StreamReader file = new System.IO.StreamReader(@"T:\\PARTS\\DATABASE\\PARTS.txt"))
        {
            while ((line = file.ReadLine()) != null)
            {
                if ((backgroundWorker1.CancellationPending == true))
                {
                    e.Cancel = true;
                }
                else if (line.Contains(partNumbersText.Text))
                {
                    Action action = () => matchesText.Text += (line + Environment.NewLine).ToString();
                    matchesText.Invoke(action); // Or use BeginInvoke


                }

            }
        }

感谢您阅读

4

4 回答 4

3

如果它是一个大文件,您将要使用 aStringBuilder而不是串联,因为字符串在幕后是不可变的,因此一遍又一遍的串联变得非常昂贵。尝试这样的事情:

using (System.IO.StreamReader file = new System.IO.StreamReader(@"T:\\PARTS\\DATABASE\\PARTS.txt"))
{
    StringBuilder strBlder = new StringBuilder();
    while ((line = file.ReadLine()) != null)
    {
        if ((backgroundWorker1.CancellationPending == true))
        {
            e.Cancel = true;
        }
        else if (line.Contains(partNumbersText.Text))
        {
           strBlder.Append(line + Environment.NewLine);
        }               
    }
    Action action = () => matchesText.Text = strBlder.ToString()
    matchesText.Invoke(action);
}

@Jim 的评论,如果你想显示文本,你可以每 x 个条目打印一次,这样它会提高一些速度,但在看到任何内容之前不必阅读整个文件:

const int ITERATIONS_PER_UI_UPDATE = 20;
using (System.IO.StreamReader file = new System.IO.StreamReader(@"T:\\PARTS\\DATABASE\\PARTS.txt"))
{
    int count = 0;
    StringBuilder strBlder = new StringBuilder();
    while ((line = file.ReadLine()) != null)
    {
        if ((backgroundWorker1.CancellationPending == true))
        {
            e.Cancel = true;
        }
        else if (line.Contains(partNumbersText.Text))
        {
           strBlder.Append(line + Environment.NewLine);
        }   
        count++;
        if ((count % ITERATIONS_PER_UI_UPDATE) == 0))
        {
             Action action = () => matchesText.Text = strBlder.ToString()
             matchesText.Invoke(action);
        }     
    }
    Action action = () => matchesText.Text = strBlder.ToString()
    matchesText.Invoke(action);
}
于 2013-07-30T21:28:55.450 回答
1

改变这个:

matchesText.Invoke(action);

对此:

matchesText.BeginInvoke(action); //Not sure about the winforms syntax for this.

因为第一个会让你的 Backgroundworker 不必要地等待 UI 刷新,而第二个不会。

于 2013-07-30T21:28:02.343 回答
0

您每次都在文件中搜索

它是浏览整个文件,contains这需要很长时间,您应该将文本加载到允许您搜索零件编号的对象中,例如字典,但您确实说它太大了,你仍然必须能够缓存一些数字,即使做这样的事情

//If there was a way to extract the parts number from each line I would do this
//but I don't know what the format is so I can't provide the code
//cache is a Dictionary>

if(!cache.ContainsKey(partsNumber.Text))
{

//then search through the file
cache.Add(partsNumber.Text,new List());

using (System.IO.StreamReader file = new System.IO.StreamReader(@"T:\\PARTS\\DATABASE\\PARTS.txt"))
            {
                while ((line = file.ReadLine()) != null)
                {
                    if ((backgroundWorker1.CancellationPending == true))
                    {
                        e.Cancel = true;
                    }
                    else if (line.Contains(partNumbersText.Text))
                    {
                        cache[partNumbersText.Text].Add(line);
                        Action action = () => matchesText.Text += (line + Environment.NewLine).ToString();
                        matchesText.Invoke(action); // Or use BeginInvoke
                    }
                }
        }
}
else //this is where you will save time
{
   foreach(var line in cache[partNumbersText.Text])
   {
       cache[partNumbersText.Text].Add(line);
       Action action = () => matchesText.Text += (line + Environment.NewLine).ToString();
       matchesText.Invoke(action); // Or use BeginInvoke
   }
}

这只是一个小小的改进

这不会使您加快很多速度,有几种方法可以使您的程序更快,最重要的一种方法是在您正在搜索的文件中建立索引。

制作索引

跟踪零件号在文件中的位置,这不是快速修复。您要做的是将具有相关部件号的行的位置保存在单独的文件中。

于 2013-07-30T22:01:38.570 回答
0

每次得到结果时不要更新文本框。使用 StringBuilder 构建您的结果对象,并仅每隔一段时间更新一次文本框。使用 ReportProgress 机制也是一个好主意,如下所示:

using (System.IO.StreamReader file = new System.IO.StreamReader(@"T:\\PARTS\\DATABASE\\PARTS.txt"))
{
    var results = new StringBuilder();
    var nextUpdate = DateTime.Now.AddMilliseconds(500);
    while ((line = file.ReadLine()) != null)
    {
        if ((backgroundWorker1.CancellationPending == true))
        {
            e.Cancel = true;
            break;
        }

        if (line.Contains(partNumbersText.Text))
        {
            results.AppendLine(line);
        }

        if (DateTime.Now > nextUpdate)
        {
            nextUpdate = DateTime.Now.AddMilliseconds(500);
            backgroundWorker1.ReportProgress(0, results.ToString());

            //move this code to the ProgressChanged event
            //matchesText.Invoke(() => matchesText.Text = results.ToString()); // Or use 
        }
    }
}

此外,.Contains() 检查 10Mb 的磁盘数据听起来很昂贵。您可以通过将文件加载到内存中来加快速度。10Mb 在现代系统上算不了什么,只要您小心避免以在 .Net 大型对象堆上创建多个条目的方式重新加载该数据,这将是迄今为止要走的路。

于 2013-07-30T21:45:59.067 回答