我正在尝试在读取文件时更新进度条。 文件大小将在200Kb到50Mb之间变化。
我正在使用System.ComponentModel.BackgroundWorker进行阅读过程,具有以下定义:
progressBar.Minimum = 0
progressBar.Maximum = System.IO.FileInfo.Length(我不关心百分比)。
阅读过程:
void worker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bg = sender as BackgroundWorker;
while (!reader.EndOfStream)
{
line = reader.ReadLine();
file_content.Add(line);
progress_precentage += line.Length + 2;
System.Threading.Thread.Sleep(100);
bg.ReportProgress(progress_precentage);
}
}
更新过程:
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar.Value = e.ProgressPercentage;
labelProgress.Content = "reading " + e.ProgressPercentage + " out of " + file_length + " bytes";
}
UI的反应非常奇怪。
对于300Kb文件,进度条和标签甚至没有更新。它们立即达到最大值。
对于50Mb文件,它们会在完成一秒钟之前更新4次。
所以我添加了System.Threading.Thread.Sleep:
while (!reader.EndOfStream)
{
line = reader.ReadLine();
file_content.Add(line);
progress_precentage += line.Length + 2;
System.Threading.Thread.Sleep(100);
bg.ReportProgress(progress_precentage);
}
这导致300Kb文件大约需要一分钟才能完成,而50Mb文件则需要大概一分钟。
当我使用System.Threading.Thread.Sleep(1)时,300Kb文件大约快一半,实际上是慢下来直到大约5秒完成。 50Mb文件需要很长时间才能完成。
当然我可以摆弄Thread.Sleep所以它会每10行左右触发一次,但性能会根据文件大小而改变。
有没有办法考虑文件大小,以便无论文件大小如何,过程将在2~3秒内完成?我知道这是可能的,因为读取一个50Mb的文件需要不到一秒的时间才能完成(没有Thread.Sleep)。
谢谢!
修改 建议后的代码(由于某种原因无法将其作为答案提交):
void worker_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker bg = sender as BackgroundWorker;
try
{
file_content = System.IO.File.ReadAllLines(file_path).ToList();
}
catch ()
{
bg.ReportProgress(-1);
file_read_successful = false;
return;
}
//For i from 0 to 100
System.Threading.Thread.Sleep(10);
bg.ReportProgress(i);
file_read_successful = true;
}
void worker_ProgressChanged(object sender, ProgressChangedEventArgs e) {
//Failure to read file
if (e.ProgressPercentage < 0)
{
//Show popup with failure message
textBlockFailure.Text = (string)e.UserState;
popupSelect.IsOpen = true;
return;
}
labelProgress.Content = e.ProgressPercentage + "%";
progressBar.Value = e.ProgressPercentage;
}
void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (file_read_successful)
{
labelProgress.Content = "Done!";
progressBar.Value = progressBar.Maximum;
}
else
{
labelProgress.Content = "";
progressBar.Value = progressBar.Minimum;
}
//Unregister events
worker.DoWork -= worker_DoWork;
worker.ProgressChanged -= worker_ProgressChanged;
worker.RunWorkerCompleted -= worker_RunWorkerCompleted;
}
答案 0 :(得分:1)
由于您尝试使进度条占用最小 3秒,无论文件大小,带宽,主机或客户端计算机上的其他进程等等,嗯,实际上只有两个选择。
第一种选择是即使在下载完成后也可以继续进度条。这有几个选项(显示100%完成剩余时间,操作以便在下载后返回不真实的值等)。
第二种选择是限制实际下载,正如您已经练习过的那样。同样,这里有许多因素可以控制您的代码。因此,我建议添加一些计算,以便了解如何节流。
要详细说明第二种选择:您已经通过限制下载所需时间的百分比来显示基本方法。您可以通过预先读取文件大小并从中进行计算来构建此基础。另一种选择是对文件进行部分下载(例如,1000行),查看需要多长时间,并推断猜测下载整个文件需要多长时间。
作为一个例子,这可能是多么困难 - 如果您已经看到MS操作系统复制文件并显示&#34;剩余时间,&#34;即使在文件传输过程中,这种情况经常是正确的还是一致的?
当然,您并未计算剩余时间,而是显示进度条。但我会坚持认为你正在遇到同样的根本障碍。
答案 1 :(得分:0)
在阅读完问题之后,我注意到的第一件事是FileInfo.Length
属性类型为long
而ProgressBar.Maximum
属性属于double
类型,所以你那里很容易出问题。
接下来我注意到的是你正在调用Thread.Sleep(100);
,这是一个糟糕的主意。 Thread.Sleep
方法将阻止UI线程,因此不是暂停执行的好方法。而不是那样,你应该尝试使用Task.Delay
method。
接下来,我注意到您对progress_precentage += line.Length + 2
的调用将导致总progress_precentage
与您之前设置的Maximum
值不匹配。如果您解决了这些问题,可能会有所帮助。
答案 2 :(得分:0)
谢谢大家的回复。
经过一夜安眠和Tony Hinkle的回应,我决定限制文件读取确实是一个坏主意。 所以我做的是读取文件,然后使用Thread.Sleep(10)更新进度条,大约需要。 2秒钟完成。
用户只能看到50Mb文件的轻微延迟,而且对于较小的文件都没有。
它有点作弊,但整体上是一个快速且用户界面友好的解决方案。
Aaron Thomas在回复中的第一选择提供了实施的总体思路,因此它是公认的答案。
再次感谢您的建议!