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

来源:互联网 发布:杭州卓森网络怎么样 编辑:程序博客网 时间:2024/06/16 11:15

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

 

相关代码: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>节点可以有多个.

 

小结

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

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 苹果6手机触摸屏失灵怎么办 苹果5s屏幕黑了怎么办 乐视手机充电慢怎么办 苹果5s触摸屏失灵怎么办 苹果6出现闪屏怎么办 苹果4s没有卡槽怎么办 苹果se触屏失灵怎么办 苹果6s屏幕乱跳怎么办 6s屏幕触摸失灵怎么办 苹果6sp屏幕失灵怎么办 苹果6s屏幕不动怎么办 苹果6s卡住了怎么办 苹果6s经常卡屏怎么办 苹果6s点不动了怎么办 手机屏自己乱点怎么办 苹果手机摔开了怎么办 苹果屏幕摔开了怎么办 苹果手机6开不了机怎么办 苹果6开不开机怎么办 苹果6s开不开机怎么办 苹果6手机开不了机怎么办 苹果6s不能开机怎么办 苹果6p无法开机怎么办 苹果6s开不了机怎么办 苹果7屏幕划不动怎么办 苹果6老是卡机怎么办 苹果手机黑屏开不了机怎么办 苹果6plus掉水里了怎么办 苹果6黑屏开不了机怎么办 苹果手机6死机了怎么办 苹果7手机死机怎么办啊 苹果7突然死机了怎么办 苹果手机5s死机怎么办 苹果六s死机了怎么办 苹果4卡机了怎么办 苹果4锁死了怎么办啊 苹果4手机停机了怎么办 苹果4开不了机怎么办 苹果4开不了机怎么办啊 苹果7手机死机了怎么办 苹果6s老是死机怎么办