[C#]实现文件复制[更新]实时显示进度条

在复制更新文件时,如果想要实时的获得文件复制的进度,并显示在窗体的进度条上有许多方法,在寻找了一段资料后,我整理了一些别人的代码,获得到本篇的代码,代码实现了根据配置文件,复制文件列表的效果.思路其实很简单,就是异步的读取和写入流,在异步回调的方法中,响应窗体的进度条控件,所有注释都写在代码中了.

 

相关代码:http://download.csdn.net/source/880686

程序界面:

  1.         int totalSize;                 //读取文件总大小
  2.         int position;                  //当前读取位置
  3.         int BUFFER_SIZE = 1024;        //缓存大小
  4.         XmlDocument xmldoc;            //配置XML文件上下文
  5.         private class _Copy
  6.         {
  7.             public string SrcFile;  //源文件
  8.             public string DstFile;  //目标文件
  9.             public Stream stream;   //流文件
  10.             public byte[] buffer;   //缓存
  11.             public int position;    //当前文件复制位置
  12.             public int Size;        //当前文件总大小
  13.         }
  14.         List<_Copy> CopyList;       //复制列表
  15.         public Form1()
  16.         {
  17.             InitializeComponent();
  18.         }
  19.         private void Form1_Load(object sender, EventArgs e)
  20.         {
  21.             xmldoc = new XmlDocument();
  22.             xmldoc.Load("config.xml");     //配置文件
  23.             CopyList = new List<_Copy>();  //复制列表
  24.             //获取所有更新列表
  25.             XmlNodeList list;
  26.             list = xmldoc.GetElementsByTagName("update");
  27.             foreach (XmlNode node in list)
  28.             {
  29.                 _Copy copy = new _Copy();
  30.                 //如果路径末尾没有/符号,则自动加上
  31.                 if (node["Path"].InnerText.Substring(node["Path"].InnerText.Length - 1, 1) != @"/")
  32.                 {
  33.                     copy.SrcFile = node["Path"].InnerText + @"/" + node["Name"].InnerText;
  34.                 }
  35.                 else
  36.                 {
  37.                     copy.SrcFile = node["Path"].InnerText + node["Name"].InnerText;
  38.                 }
  39.                 //目标文件地址
  40.                 copy.DstFile = Application.StartupPath + @"/" + node["Name"].InnerText;
  41.                 CopyList.Add(copy);
  42.             }
  43.             //如果更新列表没有值,则退出,运行程序
  44.             if (CopyList.Count <= 0)
  45.             {
  46.                 this.Close();
  47.                 return;
  48.             }
  49.             totalSize = 0;
  50.             for (int i = 0; i < CopyList.Count; i++)
  51.             {
  52.                 try
  53.                 {
  54.                     //文件不存在,继续下个文件
  55.                     if (!File.Exists(CopyList[i].SrcFile)) continue;
  56.                     //目标文件已经存在,先复制一个备份
  57.                     if (File.Exists(CopyList[i].DstFile))
  58.                     {
  59.                         File.Copy(CopyList[i].DstFile, CopyList[i].DstFile + "_upgrade"true);
  60.                         File.Delete(CopyList[i].DstFile);
  61.                     }
  62.                     FileStream fs = new FileStream(CopyList[i].SrcFile, FileMode.Open, FileAccess.Read);
  63.                     totalSize += (int)fs.Length;
  64.                     CopyList[i].Size = (int)fs.Length;
  65.                     CopyList[i].stream = fs;
  66.                     //这里是设置缓存的大小,可以根据需要修改逻辑
  67.                     BUFFER_SIZE = CopyList[i].Size / 50;
  68.                     if (BUFFER_SIZE < 10 * 1024)
  69.                     {
  70.                         BUFFER_SIZE = CopyList[i].Size / 2;
  71.                     }
  72.                     //缓存的大小要设置的比总大小要小,否则无法读取
  73.                     if (totalSize > BUFFER_SIZE)
  74.                     {
  75.                         CopyList[i].buffer = new byte[BUFFER_SIZE];
  76.                         //异步调用读取文件流
  77.                         CopyList[i].stream.BeginRead(CopyList[i].buffer, 0, BUFFER_SIZE,
  78.                             new AsyncCallback(AsyncCopyFile), CopyList[i]);
  79.                     }
  80.                     else
  81.                     {
  82.                         fs.Close();
  83.                     }
  84.                 }
  85.                 catch (Exception Ex)
  86.                 {
  87.                     //出错,恢复备份文件
  88.                     File.Copy(CopyList[i].DstFile + "_upgrade", CopyList[i].DstFile, true);
  89.                     MessageBox.Show("更新出错" + Ex.ToString());
  90.                 }
  91.             }
  92.         }
  93.         private void AsyncCopyFile(IAsyncResult ar)
  94.         {
  95.             int readedLength;
  96.             _Copy copy = (_Copy)ar.AsyncState;
  97.             try
  98.             {
  99.                 //锁顶文件流
  100.                 lock (copy.stream)
  101.                 {
  102.                     //当文件流读取完毕,获得读取的大小
  103.                     readedLength = copy.stream.EndRead(ar); 
  104.                 }
  105.                 //写入文件
  106.                 FileStream fsWriter = new FileStream(copy.DstFile, FileMode.Append, FileAccess.Write);
  107.                 fsWriter.Write(copy.buffer, 0, copy.buffer.Length);
  108.                 fsWriter.Close();
  109.                 //当前文件流位置
  110.                 lock (copy.stream)
  111.                 {
  112.                     copy.position += readedLength;
  113.                     position += readedLength;
  114.                 }
  115.                 //响应进度条
  116.                 MethodInvoker m = new MethodInvoker(SynchProgressBar);
  117.                 m.BeginInvoke(nullnull);
  118.                 //读取完毕
  119.                 if (copy.position >= copy.Size)
  120.                 {
  121.                     //关闭文件流
  122.                     copy.stream.Close(); 
  123.                     //删除备份文件
  124.                     File.Delete(copy.DstFile + "_upgrade");
  125.                     return;
  126.                 }
  127.                 //继续读取下个缓存
  128.                 lock (copy.stream)
  129.                 {
  130.                     //剩下的文件大小
  131.                     int leftSize = copy.Size - copy.position;
  132.                     //如果比缓存小,就将缓存大小设置为剩下的文件大小
  133.                     if (leftSize < BUFFER_SIZE)
  134.                         copy.buffer = new byte[leftSize];
  135.                     //继续异步读取
  136.                     copy.stream.BeginRead(copy.buffer, 0, copy.buffer.Length, new AsyncCallback(AsyncCopyFile), copy);
  137.                 }
  138.             }
  139.             catch (Exception Ex)
  140.             {
  141.                 //出错,恢复备份文件
  142.                 File.Copy(copy.DstFile + "_upgrade", copy.DstFile, true);
  143.                 MessageBox.Show("更新出错" + Ex.ToString());
  144.             }
  145.         }
  146.         public delegate void delegate_SynProgress();
  147.         private void SynchProgressBar()
  148.         {
  149.             if (this.InvokeRequired)
  150.             {
  151.                 this.Invoke(new delegate_SynProgress(SynchProgressBar));
  152.             }
  153.             else
  154.             {
  155.                 if (position >= totalSize)
  156.                 {
  157.                     this.Close();
  158.                     //下列为复制完毕后的操作,这里是启动复制文件中的第一个文件
  159.                     Process p = new Process();
  160.                     ProcessStartInfo si = new ProcessStartInfo();
  161.                     si.FileName = CopyList[0].DstFile;
  162.                     si.WindowStyle = ProcessWindowStyle.Normal;
  163.                     //为true,则用默认的打开方式打开,如果是exe等,设置为false
  164.                     si.UseShellExecute = false;  
  165.                     p.StartInfo = si;
  166.                     p.Start();
  167.                 }
  168.                 this.progressBar1.Maximum = totalSize;
  169.                 this.progressBar1.Value = position;
  170.             }
  171.         }

配置文件说明

程序的配置文件为config.xml,格式如下:

  1. <config>
  2.     <update>
  3.         <Path>C:/</Path>
  4.         <Name>1.exe</Name>
  5.     </update>
  6.     <update>
  7.         <Path>D:/</Path>
  8.         <Name>2.rar</Name>
  9.     </update>   
  10. </config>

<Path>填写复制的源路径<Name>是源文件的文件名,<update>节点可以有多个.

 

小结

程序在复制失败上做了一个备份恢复的功能,没有进行详细的测试,在异步程序中,异常的捕获要在程序块的最里层(这个和线程很相似,否则程序会因为捕获不到异常而出现程序崩溃的情况,就执行不到文件恢复了.),所以我在异步调用的回调方法中些了文件恢复的功能.程序还有很多功能没有考虑,比如,目标文件名不能更改,路径也不能更改等.

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 12
    评论
以下是使用C#编写的复制文件进度条示例代码: ```csharp using System; using System.IO; using System.Windows.Forms; public class FileCopyProgressBar : Form { private ProgressBar progressBar; private Button startButton; public FileCopyProgressBar() { Text = "File Copy Progress Bar"; progressBar = new ProgressBar(); progressBar.Dock = DockStyle.Top; Controls.Add(progressBar); startButton = new Button(); startButton.Text = "Copy File"; startButton.Dock = DockStyle.Bottom; startButton.Click += new EventHandler(OnStartButtonClicked); Controls.Add(startButton); } private void OnStartButtonClicked(object sender, EventArgs e) { string sourceFilePath = "path_to_source_file"; string destinationFilePath = "path_to_destination_file"; // Open the source file for reading using (FileStream sourceStream = new FileStream(sourceFilePath, FileMode.Open)) { // Create the destination file using (FileStream destinationStream = new FileStream(destinationFilePath, FileMode.Create)) { // Set the buffer size to 10KB byte[] buffer = new byte[10240]; int bytesRead; long totalBytesRead = 0; long fileSize = sourceStream.Length; // Copy the file and update the progress bar while ((bytesRead = sourceStream.Read(buffer, 0, buffer.Length)) > 0) { destinationStream.Write(buffer, 0, bytesRead); totalBytesRead += bytesRead; int percentComplete = (int)((double)totalBytesRead / fileSize * 100); progressBar.Value = percentComplete; Application.DoEvents(); } } } MessageBox.Show("File copied successfully!"); } public static void Main() { Application.Run(new FileCopyProgressBar()); } } ``` 在上面的示例代码中,我们创建了一个名为`FileCopyProgressBar`的窗体,其中包含一个`ProgressBar`和一个`Button`。当用户单击`Button`时,我们将复制文件到目标文件,并在进程中更新进度条。请注意,我们使用`Application.DoEvents()`来允许UI更新

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值