C# 在progressbar WPF C中异步读取大型txt文件并报告进度#

C# 在progressbar WPF C中异步读取大型txt文件并报告进度#,c#,wpf,asynchronous,progress-bar,reporting,C#,Wpf,Asynchronous,Progress Bar,Reporting,我正在尝试异步读取一个较大的txt文件(>50MB),在读取过程中,在UI进度栏上报告进度,并可以选择取消该过程。到目前为止,我已经按照我的要求读取和处理了文件async,但是我无法解决progressbar部分 public static async Task<string> ReadTxtAsync(string filePath) { try { using (var reader = File.OpenText(

我正在尝试异步读取一个较大的txt文件(>50MB),在读取过程中,在UI进度栏上报告进度,并可以选择取消该过程。到目前为止,我已经按照我的要求读取和处理了文件async,但是我无法解决progressbar部分

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

我有一个cancel
cts.cancel()的按钮点击事件但它唯一起作用的部分是创建字典。如果我放置
cancellationToken.ThrowIfCancellationRequested()进入progressbar更新部分,它仅停止更新,流读取仍在继续。如果我放置在
var readTask=reader.ReadToEndAsync()的正下方
它什么也不做。

通过定期检查Stream.position
属性,可以在读取时获取当前位置。以下方法将每100毫秒检查一次当前位置,并通过
progress
参数的
current
值进行报告。要使用此方法,请实例化proges并订阅其
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;
}
公共静态异步任务ReadTextAsync(字符串文件路径,IProgress进程)
{
使用var stream=newfilestream(filePath,FileMode.Open,FileAccess.Read);
使用var reader=newstreamreader(流);
var readTask=reader.ReadToEndAsync();
var progressTask=Task.Run(异步()=>
{
while(stream.Position
您是通过什么媒介阅读的?从现代HDD(我甚至不写SSD)读取50 Mb ReadToEndAsync文件只需不到一秒钟的时间。您甚至没有时间查看任何进度。您可以使用
StringBuilder
逐行读取文件,
ReadToEndAsync
是原子的,您无法跟踪其进度。@EldHasp我编写了50MB作为示例,目前我使用150-300MB测试它。我知道它不需要太多时间(特别是SSD),但分配说明它必须保持响应,并且必须有一个进度条,而不管文件大小。问题被错误地解决了,所提到的重复项都与异步文件读取无关,这是我在这里主要关心的问题,我关于取消ReadToEndAsync方法的问题仍然存在。@Nyariszalami您可以找到一些示例来实现取消读取方法。这取决于你。
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;
}