我不是真正的程序员,你会在这里看到,但是非常感谢能得到一些帮助来加速这个简单的搜索:
我有一些代码可以从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
}
}
}
感谢您阅读
答案 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>
跟踪文件中部件号的位置,这不是快速解决方法。您要做的是将行的位置与相关的部件号保存在一个单独的文件中。