今天项目要新增一个文件复制的功能,File.Copy() 没有好的用户体验度,所以想到使用进度条。
1 const Int32 BUFFER_SIZE = 4096; //每次拷贝4K的文件, 只考虑大于4K的文件 2 private void Read(string openPath, string savePath, ProgressBar myBar) 3 { 4 lock (openPath) 5 { 6 //返回需拷贝文件的流 7 Byte[] bytes = null; 8 Stream fsRead = new FileStream(openPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); 9 if (fsRead.Length > BUFFER_SIZE) 10 { 11 bytes = new Byte[BUFFER_SIZE]; 12 //调用异步读方法将流中的数据写到bytes数组中 13 CopyFileModel model = new CopyFileModel(); 14 model.FileStream = fsRead; 15 model.OpenFile = openPath; 16 model.SaveFile = savePath; 17 model.Bytes = bytes; 18 model.Position = 0; 19 model.TotalSize = fsRead.Length; 20 model.ObjBar = myBar; 21 fsRead.BeginRead(bytes, 0, bytes.Length, new AsyncCallback(AsyncCopyFile), model); 22 } 23 else 24 { 25 bytes = new Byte[fsRead.Length]; 26 fsRead.Read(bytes, 0, bytes.Length); 27 //将读取的数据添加到新的文件 28 FileStream fsWrite = new FileStream(savePath + Path.GetFileName(openPath), FileMode.Append, FileAccess.Write); 29 //StreamWriter write = new StreamWriter((Stream)fsWrite, false, System.Text.Encoding.Default); 30 fsWrite.Write(bytes, 0, bytes.Length); 31 fsWrite.Flush(); 32 fsWrite.Close();//关闭输出流 33 ShowProgressSchedule(myBar, fsRead.Length, 0);//显示进度 34 fsRead.Close(); //关闭输入流 35 myBar.Visible = false; 36 } 37 } 38 } 39 40 /// <summary> 41 /// 读取字节数组完成方法 42 /// </summary> 43 private void AsyncCopyFile(IAsyncResult isr) 44 { 45 Int32 readLength = 0; 46 try 47 { 48 lock (isr.AsyncState) 49 { 50 Stream stream = null; 51 CopyFileModel model = (CopyFileModel)isr.AsyncState; 52 stream = model.FileStream; 53 54 readLength = stream.EndRead(isr);//读取完成后游标的位置 55 56 model.Position += readLength; //读取数据的当前位置 57 //将读取的数据添加到新的文件 58 FileStream fsWrite = new FileStream(model.SaveFile + Path.GetFileName(model.OpenFile), FileMode.Append, FileAccess.Write); 59 fsWrite.Write(model.Bytes, 0, model.Bytes.Length); 60 fsWrite.Flush(); 61 fsWrite.Close(); 62 //在界面上显示progress的进度 63 ShowProgressSchedule((ProgressBar)model.ObjBar, model.TotalSize, model.Position); 64 //数据拷贝完成 65 if (model.Position >= model.TotalSize) 66 { 67 stream.Close(); 68 ((ProgressBar)model.ObjBar).Visible = false; 69 return; 70 } 71 Int64 leftSize = model.TotalSize - model.Position;//获得未读数据的字节大小 72 if (leftSize < BUFFER_SIZE) 73 { 74 model.Bytes = new Byte[leftSize]; 75 } 76 77 //调用异步读取函数 78 stream.BeginRead(model.Bytes, 0, model.Bytes.Length, new AsyncCallback(AsyncCopyFile), model); 79 } 80 } 81 catch (Exception ex) 82 { 83 throw ex; 84 } 85 } 86 87 delegate void ShowProgressScheduleDele(ProgressBar myBar, Int64 totalSize, Int64 position); 88 private void ShowProgressSchedule(ProgressBar myBar, Int64 totalSize, Int64 position) 89 { 90 try 91 { 92 lock (myBar) 93 { 94 // 判断是否在线程中访问 95 if (!myBar.InvokeRequired) 96 { 97 // 不是的话直接操作控件 98 myBar.Maximum = (Int32)totalSize; 99 myBar.Value = (Int32)position; 100 } 101 else 102 { 103 // 是的话启用delegate访问 104 ShowProgressScheduleDele showProgress = new ShowProgressScheduleDele(ShowProgressSchedule); 105 // 如使用Invoke会等到函数调用结束,而BeginInvoke不会等待直接往后走 106 this.BeginInvoke(showProgress, new object[] { myBar, totalSize, position }); 107 } 108 } 109 } 110 catch (Exception ex) 111 { 112 throw ex; 113 } 114 }
调用:
String savePath = @"\\picserver\pack\data\"; //保存文件的路径 String openPath1 = @"\\dltfile01\pack\data\bg6_yz.dbf"; //打开文件的路径 String openPath2 = @"\\dltfile01\pack\data\bg6_yz.cdx"; //打开文件的路径 private void uButton5_Click(object sender, EventArgs e) { try { if (File.Exists(openPath1) && File.Exists(openPath2)) { File.Delete(savePath + "bg6_yz.dbf"); File.Delete(savePath + "bg6_yz.cdx"); this.progressBar1.Visible = true; this.progressBar2.Visible = true; Read(openPath1, savePath, this.progressBar1); Read(openPath2, savePath, this.progressBar2); } else { UMessageBox.Show("找不到目标文件路径!"); } } catch (Exception ex) { UMessageBox.Show("复制文件时出现以下错误:\r\n" + ex); this.progressBar1.Visible = false; this.progressBar2.Visible = false; } }