簡體   English   中英

復制大文件時更新進度條

[英]Update progress bar while copying a large file

我正在尋找一種在將文件從一個位置復制到另一個位置時更新進度欄的方法。

我正在BackgroundWorker進行復制,並且進度條也在后台更新。 我嘗試使用file.length來獲取文件大小,並使用該百分比來工作百分比並以這種方式更新條形,但並不高興。

我附上了代碼,非常感謝您的幫助,謝謝。

namespace Copier

{公共局部類Form1:表單{公共Form1(){InitializeComponent(); }

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

還是有人可以向我展示一種使進度條自行運行以表明表單尚未凍結的方法?

清理了代碼

感謝您到目前為止的投入

我認為僅調用CopyFileEx是最簡單的方法,它允許您指定進度處理程序,以便在復制文件時從OS獲取更新。 這是從pinvoke.net頁面復制的CopyFileEx示例代碼:

[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;
}

這不能在多個級別上使用。 首先,需要通過WorkerReportsProgress將后台工作人員設置為“報告更改”,但是此標志並不意味着他可以自動執行此操作,當然這是行不通的。 為此,Worker提供了ReportProgress方法,您需要調用該方法以顯示當前進度。 這揭示了您方法的最終缺陷。 File.Copy方法正在阻止,但是您的工作人員需要時間才能調用ReportProgress方法。 因此,您需要找到一種異步復制文件的方法。 這個問題可能會有所幫助,Dave Bishs的評論當然是異步文件復制的很好參考。

我的建議是將btnCopyTo_ClickbtnCopyFrom_Click的內容移動到每個單獨的DoWork后台工作程序,然后使用btnCopyTo_ClickbtnCopyFrom_Click觸發后台工作程序。 后台工作人員可以用來報告進度,因此您不這樣做就什至無法開始。

至於何時真正更新進度條,我建議每次確定要復制的文件的大小。

如果隨后將文件分成一定大小的塊,然后使用循環一次復制一個塊,則無論循環有多少循環,都應該能夠將進度條增加一定的數量。

或者,找到一種具有異步線程的方法,該線程在進行復制時將進度條從0連續循環到100。 這是一個非常基本的解決方案,但至少可以讓用戶知道正在發生的事情。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM