异步读取大型 txt 文件并在进度条 WPF C# 中报告进度
Reading large txt file async and reporting progress in progressbar WPF C#
我正在尝试异步读取一个大的 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";
}
我有一个用于取消的 buttonClick 事件 cts.Cancel();
但它唯一起作用的部分是字典创建。如果我将 cancellationToken.ThrowIfCancellationRequested();
放入进度条更新部分,它只会停止更新,流读取仍在继续。如果我放置在 var readTask = reader.ReadToEndAsync();
正下方,它什么都不做。
您可以通过定期检查Stream.Position
属性 来获取阅读时的当前位置。以下方法将每 100 毫秒检查一次当前位置,并通过 progress
参数的 current
值报告。要使用此方法,请实例化 Progess<(double current, double total)> 并订阅其 ProgressChanged
事件。
public static async Task<string> ReadTextAsync(string filePath, IProgress<(double current, double total)> progress)
{
using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
using var reader = new StreamReader(stream);
var readTask = reader.ReadToEndAsync();
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;
}
我正在尝试异步读取一个大的 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";
}
我有一个用于取消的 buttonClick 事件 cts.Cancel();
但它唯一起作用的部分是字典创建。如果我将 cancellationToken.ThrowIfCancellationRequested();
放入进度条更新部分,它只会停止更新,流读取仍在继续。如果我放置在 var readTask = reader.ReadToEndAsync();
正下方,它什么都不做。
您可以通过定期检查Stream.Position
属性 来获取阅读时的当前位置。以下方法将每 100 毫秒检查一次当前位置,并通过 progress
参数的 current
值报告。要使用此方法,请实例化 Progess<(double current, double total)> 并订阅其 ProgressChanged
事件。
public static async Task<string> ReadTextAsync(string filePath, IProgress<(double current, double total)> progress)
{
using var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read);
using var reader = new StreamReader(stream);
var readTask = reader.ReadToEndAsync();
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;
}