夏日部落客BloggerAds《2008‧夏》

2008年4月17日 星期四

C# 複製檔案進度列實作 (Copy file + Progress Bar)

應用程式常常會有搬移檔案的動作,但複製檔案時若沒有處裡,很容易造成使用者介面沒回應的畫面,此外若涉及複製大檔案,通常需要顯示進度列,便於使用者知道現在的複製進度,是要繼續下去或者是去取消,這一類的問題,有幾個要注意的問題(1)UI的同步更新問題,(2)非同步複製檔案的實作,我相信這問題已經是老掉牙的問題,但是我在網路上找到的例子大都是這一個使用C#在进度条中显示复制文件的进度 (大部分都是貼這個範例),我大概看過且稍為用了一下(我的開發平台是VS2008),發現有一個問題是他在更新ProgressBar的時候,會有InvalidOperationException[Cross-Thread operation not vaild... 的問題產生,這問題可以上Google稍微查一下就發現問題所在,所以我稍微改寫了一下,畫面及程式碼如下:

Copy

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        int totalSize;  //Total Size
        int position;   //Position
        const int BUFFER_SIZE = 4096;
        byte[] buffer;
        FileStream fileWriteStream;
        FileStream fileReadStream;
        public Form1()
        {
            InitializeComponent();
        }

        private void ctrlCopy_Click(object sender, EventArgs e)
        {
            string strFile = "";
            position = 0;
            totalSize = 0;
            OpenFileDialog openDialog = new OpenFileDialog();
            if (openDialog.ShowDialog() == DialogResult.OK)
                strFile = openDialog.FileName;
            else
                return;

            // Reset Status in order to prevent another copying process
            this.totalSize = 0;
            this.position = 0;
            if (this.buffer != null) this.buffer = null;
            if (this.fileWriteStream != null) this.fileWriteStream.Close();
            if (this.fileReadStream != null) this.fileReadStream.Close();

            //Delete file which aready exists.
            if (System.IO.File.Exists("c:\\copyedFile.bin"))
                System.IO.File.Delete("c:\\copyedFile.bin");

            this.fileReadStream = new FileStream(strFile, FileMode.Open, FileAccess.Read);
            this.fileWriteStream = new FileStream("C:\\copyedFile.bin", FileMode.Append, FileAccess.Write);
            totalSize = (int)fileReadStream.Length;
            this.progressBar1.Maximum = totalSize;

            //Copy file while larger than 4KB.
            if (totalSize > BUFFER_SIZE)
            {
                buffer = new byte[BUFFER_SIZE];

                // Async Invoke
                fileReadStream.BeginRead(buffer, 0, BUFFER_SIZE, new AsyncCallback(AsyncCopyFile), null);
            }
            else
            {
                this.fileReadStream.Close();
            }
        }
        // Asynchronously copy file
        private void AsyncCopyFile(IAsyncResult ar)
        {
            int readedLength;

            // Lock FileStream
            lock (this.fileReadStream)
            {
                readedLength = this.fileReadStream.EndRead(ar);   // When stream endread, get readed length
            }

            // Write to disk
            this.fileWriteStream.Write(buffer, 0, buffer.Length);

            // Current stream position
            position += readedLength;

            // Response UI
            MethodInvoker m = new MethodInvoker(SynchProgressBar);
            if (this.progressBar1.InvokeRequired)
            {
                this.progressBar1.Invoke(m);
            }

            if (position >= totalSize) // Read over.
            {
                this.fileWriteStream.Close();        //Close FileStream 
                this.fileReadStream.Close();
                return;
            }

            // Continue to read and write
            lock (this.fileReadStream)
            {
                int leftSize = totalSize - position;

                if (leftSize < BUFFER_SIZE)
                    buffer = new byte[leftSize];

                this.fileReadStream.BeginRead(buffer, 0, buffer.Length, new AsyncCallback(AsyncCopyFile), null);
            }
        }

        private void SynchProgressBar()
        {
            this.progressBar1.Value = position;
        }
    }
}

不過細看有一些細節的部份要處裡,如檔案小於4KB時要如何處理,若要將此方法包成物件,要如何用delegate or event傳給上層UI... 這些問題就交給各位看官嚕。 此外有些觀念也是很重要的,在此附上連結: http://www.cnblogs.com/c2303191/articles/826571.html

0 意見: