【问题标题】:Reading large txt file async and reporting progress in progressbar WPF C# [duplicate]在进度条WPF C#中异步读取大型txt文件并报告进度[重复]
【发布时间】: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


【解决方案1】:

您可以在阅读时通过定期检查Stream.Position属性来获取当前位置。以下方法将每 100 毫秒检查一次当前位置,并通过 progress 参数的 current 值报告它。要使用此方法,请实例化 Progess 并订阅其 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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多