Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 复制大文件时更新进度条_C#_.net_Visual Studio 2010 - Fatal编程技术网

C# 复制大文件时更新进度条

C# 复制大文件时更新进度条,c#,.net,visual-studio-2010,C#,.net,Visual Studio 2010,我正在寻找一种在将文件从一个位置复制到另一个位置时更新进度条的方法 我在BackgroundWorker中进行复制,并在后台更新进度条。我已经尝试使用file.length来获得文件大小,并使用它来计算百分比和更新栏,但没有乐趣 我附上代码和任何帮助将不胜感激,谢谢你 namespace Copier { 公共部分类Form1:Form { 公共表格1() { 初始化组件(); } // Declare for use in all methods public string

我正在寻找一种在将文件从一个位置复制到另一个位置时更新进度条的方法

我在
BackgroundWorker
中进行复制,并在后台更新进度条。我已经尝试使用file.length来获得文件大小,并使用它来计算百分比和更新栏,但没有乐趣

我附上代码和任何帮助将不胜感激,谢谢你

namespace Copier
{ 公共部分类Form1:Form { 公共表格1() { 初始化组件(); }

    // Declare for use in all methods
    public string copyFrom;
    public string copyTo;

    private void btnCopyFrom_Click(object sender, EventArgs e)
    {
        // uses a openFileDialog, openFD, to chose the file to copy
        copyFrom = "";

        openFD.InitialDirectory = @"C:\Documents and Settings\user\My Documents";
        openFD.FileName = "";

        //openFD.ShowDialog();

        if (openFD.ShowDialog() == DialogResult.Cancel)
        {
            MessageBox.Show("cancel button clicked");
        }

        else
        {
            // sets copyFrom = to the file chosen from the openFD
            copyFrom = openFD.FileName;
            // shows it in a textbox
            txtCopyFrom.Text = copyFrom;
        }
    }

    private void btnCopyTo_Click(object sender, EventArgs e)
    {
        //uses folderBrowserDialog, folderBD, to chose the folder to copy to
        copyTo = "";

        this.folderBD.RootFolder = System.Environment.SpecialFolder.MyComputer;
        this.folderBD.ShowNewFolderButton = false;
        //folderBD.ShowDialog();
        //DialogResult result = this.folderBD.ShowDialog();

        if (folderBD.ShowDialog() == DialogResult.Cancel)
        {
            MessageBox.Show("cancel button clicked");
        }
        else
        {
            // sets copyTo = to the folder chosen from folderBD
            copyTo = this.folderBD.SelectedPath;
            //shows it in a textbox.
            txtCopyTo.Text = copyTo;
        }
    }

    private void btnCopy_Click(object sender, EventArgs e)
    {
        copyBGW.RunWorkerAsync();
    }

    private void btnCancel_Click(object sender, EventArgs e)
    {
        Application.Exit();
    }

    //=================================================================
    //                      BackGroundWorkers
    //=================================================================

    private void copyBGW_DoWork(object sender, DoWorkEventArgs e)
    {
        try
        {
            // copies file
            string destinatationPath = Path.Combine(copyTo, Path.GetFileName(copyFrom));
            File.Copy(copyFrom, destinatationPath);
            MessageBox.Show("File Copied");
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message);
        }
    }
}
或者有人能告诉我一种方法,让进度条自行运行,这样它就可以显示表单没有冻结

已经清除了代码


感谢到目前为止的输入

这无法在多个级别上工作。首先,需要将后台工作人员设置为“报告更改”via,但此标志并不意味着他可以自动执行此操作,当然这不起作用。因此,工作人员提供了您需要调用该方法以显示当前进度的方法。这揭示了您的方法的最后一个缺陷。File.Copy方法正在阻塞,但您的工作人员需要时间调用ReportProgress方法。因此,您不需要o找到一种异步复制文件的方法。这个问题可能会有所帮助,当然Dave Bishs评论是异步文件复制的一个很好的参考。

我的建议是将
btnCopyTo\u单击
btnCopyFrom\u单击
的内容移动到单独的DoWork后台工作人员,然后使用
btnCopyTo\u单击
btnCopyFrom_单击
触发后台工作程序。后台工作程序可用于报告进度,因此不这样做您甚至无法开始

至于何时实际更新进度条,我建议每次确定要复制的文件的大小

如果随后将文件拆分为特定大小的块,然后使用循环一次复制一个块,那么无论循环多少次,您都应该能够将进度条增加一定数量


或者,找到一种方法,让一个异步线程在复制过程中从0到100连续循环进度条。这是一个非常基本的解决方案,但它至少让用户知道发生了什么。

我认为调用CopyFileEx最简单,它允许您指定进度处理程序因此,您可以在复制文件时从操作系统获得更新。以下是从pinvoke.net页面复制的示例代码:


下面是如何复制文件并报告进度的另一个示例:,BackgroundWorker的DoWork eventhandler可能看起来像这里的copy方法,用对BackgroundWorker的ReportProgress方法的调用替换OnProgressChanged调用。@Renaud Dumont我不确定使用streams创建自己的复制方法是否明智。我认为实际的复制方法对于这种io操作更有效,但我没有这方面的参考。但是,是的,如果对实际的复制进行某种优化,这可能就是为什么没有异步版本的原因。首先感谢您的输入。我不是世界上最伟大的程序员,只是y在一两周前开始学习c#。我知道第一个代码中充满了一些愚蠢的小错误,我把它们放进去是为了帮助展示我正在尝试做什么。我使用“progressBar1.Style=ProgressBarStyle.Marquee;”来显示程序没有冻结,并且在文件复制和复制时标签会发生变化。再次感谢对于输入,我知道我的解决方案比我要求的要简单得多,但我无法完全理解异步。从技术上说,这仍然会阻止调用线程,但这确实是一种从文件复制、取消和“重新启动”行为(这可能是不可取的,请小心)中获得进展的好方法.但对FileCopyEX的调用会阻止调用线程,直到复制完成或取消。但这并不妨碍您更新表单上的进度条。
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool CopyFileEx(string lpExistingFileName, string lpNewFileName,
   CopyProgressRoutine lpProgressRoutine, IntPtr lpData, ref Int32 pbCancel,
   CopyFileFlags dwCopyFlags);

delegate CopyProgressResult CopyProgressRoutine(
long TotalFileSize,
long TotalBytesTransferred,
long StreamSize,
long StreamBytesTransferred,
uint dwStreamNumber,
CopyProgressCallbackReason dwCallbackReason,
IntPtr hSourceFile,
IntPtr hDestinationFile,
IntPtr lpData);

int pbCancel;

enum CopyProgressResult : uint
{
    PROGRESS_CONTINUE = 0,
    PROGRESS_CANCEL = 1,
    PROGRESS_STOP = 2,
    PROGRESS_QUIET = 3
}

enum CopyProgressCallbackReason : uint
{
    CALLBACK_CHUNK_FINISHED = 0x00000000,
    CALLBACK_STREAM_SWITCH = 0x00000001
}

[Flags]
enum CopyFileFlags : uint
{
    COPY_FILE_FAIL_IF_EXISTS = 0x00000001,
    COPY_FILE_RESTARTABLE = 0x00000002,
    COPY_FILE_OPEN_SOURCE_FOR_WRITE = 0x00000004,
    COPY_FILE_ALLOW_DECRYPTED_DESTINATION = 0x00000008
}

private void XCopy(string oldFile, string newFile)
{
    CopyFileEx(oldFile, newFile, new CopyProgressRoutine(this.CopyProgressHandler), IntPtr.Zero, ref pbCancel, CopyFileFlags.COPY_FILE_RESTARTABLE);
}

private CopyProgressResult CopyProgressHandler(long total, long transferred, long streamSize, long StreamByteTrans, uint dwStreamNumber,CopyProgressCallbackReason reason, IntPtr hSourceFile, IntPtr hDestinationFile, IntPtr lpData)
{
    return CopyProgressResult.PROGRESS_CONTINUE;
}