【发布时间】:2021-05-03 11:58:50
【问题描述】:
我正在尝试异步读取一个大的 txt 文件 (>50MB),当它正在读取时,在 UI 进度条上报告进度并可以选择取消该过程。到目前为止,我已经按照我的意愿读取并处理了文件异步,但我无法解决进度条部分。
public static async Task<string> ReadTxtAsync(string filePath)
{
try
{
using (var reader = File.OpenText(filePath))
{
var content = await reader.ReadToEndAsync();
return content;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
return null;
}
}
public static async Task<Dictionary<string, int>> OpenTxtAsync()
{
Dictionary<string, int> uniqueWords = new Dictionary<string, int>();
OpenFileDialog openFileDialog = new OpenFileDialog();
openFileDialog.Filter = "Text Documents (*.txt)|*.txt";
string content = null;
try
{
if (openFileDialog.ShowDialog() == true)
{
string filePath = openFileDialog.FileName.ToString();
if (openFileDialog.CheckFileExists && new[] { ".txt" }.Contains(Path.GetExtension(filePath).ToLower()) && filePath != null)
{
Task<string> readText = ReadTxtAsync(filePath);
content = await readText;
uniqueWords = WordExtractor.CountWords(ref content);
}
else MessageBox.Show("Please use .txt format extension!");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
return uniqueWords;
}
private async void LoadFileButtonClick(object sender, RoutedEventArgs e)
{
Task<Dictionary<string, int>> dictionaryContent = TextFileLoader.OpenTxtAsync();
uniqueWords = await dictionaryContent;
UpdateListView();
}
如何查看ReadToEndAsync() 当前的位置?我怎样才能让它不断更新进度条,我怎样才能取消它?
编辑: 感谢@emoacht,我设法让进度条正确更新并显示其百分比。剩下的唯一事情就是取消任务,我根据 Tim Corey 的视频尝试过,但它对我的代码不起作用。
public static async Task<string> ReadTextAsync(string filePath, IProgress<(double current, double total)> progress, CancellationToken cancellationToken)
{
using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
using var reader = new StreamReader(stream);
var readTask = reader.ReadToEndAsync();
cancellationToken.ThrowIfCancellationRequested();
var progressTask = Task.Run(async () =>
{
while (stream.Position < stream.Length)
{
await Task.Delay(TimeSpan.FromMilliseconds(100));
progress.Report((stream.Position, stream.Length));
}
});
await Task.WhenAll(readTask, progressTask);
return readTask.Result;
}
try
{
Task<string> readText = TextFileLoader.ReadTextAsync(filePath, progress, cts.Token);
content = await readText;
LabelProgress.Content = "Done Reading! Now creating wordlist...";
}
catch (OperationCanceledException)
{
LabelProgress.Content = "File laden wurde abgebrochen";
}
我有一个用于取消 cts.Cancel(); 的 buttonClick 事件,但它唯一起作用的部分是字典创建。如果我将cancellationToken.ThrowIfCancellationRequested(); 放入进度条更新部分,它只会停止更新,流读取仍然继续。如果我放置在var readTask = reader.ReadToEndAsync(); 的正下方,它什么也不做。
【问题讨论】:
-
您在阅读什么媒体?从现代 HDD(我什至不写关于 SSD 的文章),读取 50 Mb ReadToEndAsync 文件将花费不到一秒的时间。你甚至没有时间看到任何进展。
-
您可以使用
StringBuilder并逐行读取文件,ReadToEndAsync是原子的,您无法跟踪它的进度。 -
@EldHasp 我写了 50MB 作为例子,目前我用 150-300MB 测试它。我知道它不需要那么多时间(尤其是使用 SSD),但任务说明它必须保持响应并且必须有一个进度条,无论文件大小如何。
-
问题被错误地关闭了,提到的重复项都与异步文件读取无关,这是我在这里主要关心的问题,我关于取消 ReadToEndAsync 方法的问题仍然存在。跨度>
-
@Nyariszalami 您可以找到一些示例来实现取消读取方法。这取决于你。
标签: c# wpf asynchronous progress-bar reporting