RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1423061
Accepted
tomato-magnet-regulato
tomato-magnet-regulato
Asked:2022-08-23 14:01:11 +0000 UTC2022-08-23 14:01:11 +0000 UTC 2022-08-23 14:01:11 +0000 UTC

异步复制配合progressBar'om

  • 772

其实任务已经完成了一半,我有现成的解决方案,不是没有帮助backgoundWorker:

复制功能:

private void copy_file(string source_, string des)
        {
                FileStream fsOut = new FileStream(des, FileMode.Create);
                FileStream fsIn = new FileStream(source_, FileMode.Open);
                byte[] bt = new byte[1048756];
                int readByte;

                while ((readByte = fsIn.Read(bt, 0, bt.Length)) > 0)
                {
                    fsOut.Write(bt, 0, readByte);
                    backgroundWorker1.ReportProgress((int)(fsIn.Position * 100 / fsIn.Length));
                }
                fsIn.Close();
                fsOut.Close();
        }

做工作:

private void Worker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
        {
            copy_file(server_path + filename, Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + "\\" + filename);
        }

RunWorker 已完成:

private void Worker_RunWorkerCompleted(object sender, System.ComponentModel.RunWorkerCompletedEventArgs e)
        {
            if (e.Error == null)
            {               
                err_msg.Text = "Файл находится на рабочем столе!";
            }
            else
            {
                err_msg.Text = "Произошла ошибка.";
            }
            download_sound.Enabled = true;           
        }

进度改变:

private void Worker_ProgressChanged(object sender, System.ComponentModel.ProgressChangedEventArgs e)
        {
            progressBar1.Value = e.ProgressPercentage;
            err_msg.Text = progressBar1.Value.ToString() + "%";
        }

点击按钮:

Worker.RunWorkerAsync();

上面的方法效果很好,但是当在异步函数中使用这个方法时(比如private async void button_click()),我得到了一个线程排队的效果,嗯......文件被复制 - 放在正确的文件夹中 - 进度条立即填满。我试图通过网络复制,同样的麻烦。但幸运的是,当async你btn外出时它可以工作。

现在说重点:

因为 最初,我的计划是使用async\await方法,我切换到这种文件复制:

public async Task CopyFilesAsync(StreamReader Source, StreamWriter Destination)
        {
            char[] buffer = new char[0x1000];
            int numRead;
            while ((numRead = await Source.ReadAsync(buffer, 0, buffer.Length)) != 0)
            {
                await Destination.WriteAsync(buffer, 0, numRead);
            }
        }

_

public async Task CopyFile(string startDirectoy, string endDirectory)
        {
            using (StreamReader SourceReader = File.OpenText(startDirectoy))
            {
                using (StreamWriter DestinationWriter = File.CreateText(endDirectory))
                {
                    await CopyFilesAsync(SourceReader, DestinationWriter);
                    SourceReader.Close();
                    DestinationWriter.Close();
                }
            }
        }

我只是不知道如何让progressBar 执行我的任务。我也无法到达 StreamReader.Position 使用:

progressBar1.Value=(int)((StreamReader.BaseStream.Position/StreamReader.BaseStream.Length)*100);

我没有成功。ProgressBar 与一切分开为我工作>< 如果您有一些提示,请给他们,我将非常感激!

在此处输入图像描述

c# winforms
  • 1 1 个回答
  • 68 Views

1 个回答

  • Voted
  1. Best Answer
    aepot
    2022-08-23T16:39:14Z2022-08-23T16:39:14Z

    我有一个下载文件的例子,为什么不重写它来复制

    • 异步复制文件
    • 通过单击取消按钮,您可以停止复制
    • button1- 复制按钮,button2- 取消按钮,progressBar1- 进度条
    • 使用 IProgress 接口和 Progress 类实现了一个进度报告
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            button2.Enabled = false;
        }
    
        // Токен отмены служит для прерывания работы копирования в любой момент
        private CancellationTokenSource _cts;
    
        private async Task CopyFileAsync(string srcPath, string dstPath, IProgress<int> status, CancellationToken token)
        {
            const int bufferLength = 16384;
    
            using FileStream src = File.OpenRead(srcPath);
            using FileStream dst = File.Create(dstPath);
            long currentPosition = 0;
            long contentLength = src.Length;
            int progress = -1;
            int oldProgress;
            byte[] buffer = new byte[bufferLength];
            int bytesReceived;
            while ((bytesReceived = await src.ReadAsync(buffer, 0, bufferLength, token).ConfigureAwait(false)) > 0)
            {
                await dst.WriteAsync(buffer, 0, bytesReceived, token).ConfigureAwait(false);
    
                currentPosition += bytesReceived;
                oldProgress = progress;
                progress = (int)(currentPosition * 100 / contentLength);
                // так как значение от 0 до 100, нет особого смысла повтороно обновлять интерфейс, если значение не изменилось.
                if (oldProgress != progress)
                {
                    status?.Report(progress);
                }
            }
        }
    
        private async void button1_Click(object sender, EventArgs e)
        {
            if (_cts != null)
                return;
            button1.Enabled = false;
            button2.Enabled = true;
    
            using (_cts = new CancellationTokenSource())
            {
                try
                {
                    await CopyFileAsync("file1.txt", "file2.txt", new Progress<int>(v => { progressBar1.Value = v; }), _cts.Token);
                }
                catch (OperationCanceledException) { } // была отмена, ничего не делать
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString(), ex.GetType().Name);
                }
                progressBar1.Value = 0;
            }
            _cts = null;
    
            button1.Enabled = true;
            button2.Enabled = false;
        }
    
        private void button2_Click(object sender, EventArgs e)
        {
            _cts?.Cancel();
        }
    }
    

    考虑到winform进度条的慢动画来更新进度

    private async Task CopyFileAsync(string srcPath, string dstPath, IProgress<int> status, CancellationToken token)
    {
        const int bufferLength = 16384;
    
        using FileStream src = File.OpenRead(srcPath);
        using FileStream dst = File.Create(dstPath);
        long currentPosition = 0;
        long contentLength = src.Length;
        int progress = -1;
        int oldProgress;
        byte[] buffer = new byte[bufferLength];
        int bytesReceived;
    
        long elapsed = 0;
        var sw = Stopwatch.StartNew();
    
        while ((bytesReceived = await src.ReadAsync(buffer, 0, bufferLength, token).ConfigureAwait(false)) > 0)
        {
            await dst.WriteAsync(buffer, 0, bytesReceived, token).ConfigureAwait(false);
    
            currentPosition += bytesReceived;
            oldProgress = progress;
            progress = (int)(currentPosition * 100 / contentLength);
            
            // 1 / 30 = 0.033 - 30 кадров в секунду
            if (oldProgress != progress && (progress == 100 || sw.ElapsedMilliseconds - 33 > elapsed))
            {
                status?.Report(progress);
                elapsed = sw.ElapsedMilliseconds;
            }
        }
    }
    

    @PavelMayorov 关于立即开始在线程池中复制的建议可以这样实现

    IProgress<int> status = new Progress<int>(v => { progressBar1.Value = v; });
    await Task.Run(() => CopyFileAsync("file1.txt", "file2.txt", status, _cts.Token));
    
    • 1

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    我看不懂措辞

    • 1 个回答
  • Marko Smith

    请求的模块“del”不提供名为“default”的导出

    • 3 个回答
  • Marko Smith

    "!+tab" 在 HTML 的 vs 代码中不起作用

    • 5 个回答
  • Marko Smith

    我正在尝试解决“猜词”的问题。Python

    • 2 个回答
  • Marko Smith

    可以使用哪些命令将当前指针移动到指定的提交而不更改工作目录中的文件?

    • 1 个回答
  • Marko Smith

    Python解析野莓

    • 1 个回答
  • Marko Smith

    问题:“警告:检查最新版本的 pip 时出错。”

    • 2 个回答
  • Marko Smith

    帮助编写一个用值填充变量的循环。解决这个问题

    • 2 个回答
  • Marko Smith

    尽管依赖数组为空,但在渲染上调用了 2 次 useEffect

    • 2 个回答
  • Marko Smith

    数据不通过 Telegram.WebApp.sendData 发送

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5