从文件中读取文本的性能非常慢,我想知道原因

时间:2013-07-30 21:23:32

标签: c#

我不是真正的程序员,你会在这里看到,但是非常感谢能得到一些帮助来加速这个简单的搜索:

我有一些代码可以从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 个答案:

答案 0 :(得分:3)

如果它是一个大文件,你会想要使用StringBuilder而不是连接,因为字符串在封面下是不可变的,所以反复连接变得非常昂贵。尝试这样的事情:

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);
}

答案 1 :(得分:1)

改变这个:

matchesText.Invoke(action);

到此:

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

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

答案 2 :(得分: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大对象堆上创建多个条目的方式重新加载这些数据,这将是迄今为止的方法。 / p>

答案 3 :(得分: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
   }
}

这只是一个小改进

这不会让你加速那么多,有一些方法可以让你的程序更快,最有意义的就是在你正在搜索的文件中建立一个索引。 / p>

制作索引

跟踪文件中部件号的位置,这不是快速解决方法。您要做的是将行的位置与相关的部件号保存在一个单独的文件中。