Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

File Copy with Progress Bar

I used this code:

using System; using System.Collections.Generic; using System.ComponentModel; using System.Windows.Forms; using System.IO;  namespace WindowsApplication1 {   public partial class Form1 : Form {     // Class to report progress     private class UIProgress {       public UIProgress(string name_, long bytes_, long maxbytes_) {         name = name_; bytes = bytes_; maxbytes = maxbytes_;       }       public string name;       public long bytes;       public long maxbytes;     }     // Class to report exception {     private class UIError {       public UIError(Exception ex, string path_) {         msg = ex.Message; path = path_; result = DialogResult.Cancel;       }       public string msg;       public string path;       public DialogResult result;     }     private BackgroundWorker mCopier;     private delegate void ProgressChanged(UIProgress info);     private delegate void CopyError(UIError err);     private ProgressChanged OnChange;     private CopyError OnError;      public Form1() {       InitializeComponent();       mCopier = new BackgroundWorker();       mCopier.DoWork += Copier_DoWork;       mCopier.RunWorkerCompleted += Copier_RunWorkerCompleted;       mCopier.WorkerSupportsCancellation = true;       OnChange += Copier_ProgressChanged;       OnError += Copier_Error;       button1.Click += button1_Click;       ChangeUI(false);     }      private void Copier_DoWork(object sender, DoWorkEventArgs e) {       // Create list of files to copy       string[] theExtensions = { "*.jpg", "*.jpeg", "*.bmp", "*.png", "*.gif" };       List<FileInfo> files = new List<FileInfo>();       string path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);       DirectoryInfo dir = new DirectoryInfo(path);       long maxbytes = 0;       foreach (string ext in theExtensions) {         FileInfo[] folder = dir.GetFiles(ext, SearchOption.AllDirectories);         foreach (FileInfo file in folder) {           if ((file.Attributes & FileAttributes.Directory) != 0) continue;           files.Add(file);           maxbytes += file.Length;         }       }       // Copy files       long bytes = 0;       foreach (FileInfo file in files) {         try {           this.BeginInvoke(OnChange, new object[] { new UIProgress(file.Name, bytes, maxbytes) });           File.Copy(file.FullName, @"c:\temp\" + file.Name, true);         }         catch (Exception ex) {           UIError err = new UIError(ex, file.FullName);            this.Invoke(OnError, new object[] { err });           if (err.result == DialogResult.Cancel) break;         }         bytes += file.Length;       }     }     private void Copier_ProgressChanged(UIProgress info) {       // Update progress       progressBar1.Value = (int)(100.0 * info.bytes / info.maxbytes);       label1.Text = "Copying " + info.name;     }     private void Copier_Error(UIError err) {       // Error handler       string msg = string.Format("Error copying file {0}\n{1}\nClick OK to continue copying files", err.path, err.msg);       err.result = MessageBox.Show(msg, "Copy error", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation);     }     private void Copier_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {       // Operation completed, update UI       ChangeUI(false);     }     private void ChangeUI(bool docopy) {       label1.Visible = docopy;       progressBar1.Visible = docopy;       button1.Text = docopy ? "Cancel" : "Copy";       label1.Text = "Starting copy...";       progressBar1.Value = 0;     }     private void button1_Click(object sender, EventArgs e) {       bool docopy = button1.Text == "Copy";       ChangeUI(docopy);       if (docopy) mCopier.RunWorkerAsync();       else mCopier.CancelAsync();     }   } } 

posted here (the one that nobugz posted) in copying files and displaying the status in progress bar.

I wanted to continuously increment the value of the progress bar while copying, especially large files. What happens in this sample code is that the value in progress bar stops on every file copied and after one file has been copied it will then increment to the size of the next file to be copied. I wanted it to work like CopyFileEx in Windows that progress bar continuously increment when copying (I cant use CopyFileEx because I wanted to have my own implementation).

like image 218
patlimosnero Avatar asked May 18 '11 12:05

patlimosnero


2 Answers

You need something like this:

    public delegate void ProgressChangeDelegate(double Percentage, ref bool Cancel);     public delegate void Completedelegate();      class CustomFileCopier     {         public CustomFileCopier(string Source, string Dest)         {             this.SourceFilePath = Source;             this.DestFilePath = Dest;              OnProgressChanged += delegate { };             OnComplete += delegate { };         }          public void Copy()         {             byte[] buffer = new byte[1024 * 1024]; // 1MB buffer             bool cancelFlag = false;              using (FileStream source = new FileStream(SourceFilePath, FileMode.Open, FileAccess.Read))             {                 long fileLength = source.Length;                 using (FileStream dest = new FileStream(DestFilePath, FileMode.CreateNew, FileAccess.Write))                 {                     long totalBytes = 0;                     int currentBlockSize = 0;                      while ((currentBlockSize = source.Read(buffer, 0, buffer.Length)) > 0)                     {                         totalBytes += currentBlockSize;                         double percentage = (double)totalBytes * 100.0 / fileLength;                          dest.Write(buffer, 0, currentBlockSize);                          cancelFlag = false;                         OnProgressChanged(percentage, ref cancelFlag);                          if (cancelFlag == true)                         {                             // Delete dest file here                             break;                         }                     }                 }             }              OnComplete();         }          public string SourceFilePath { get; set; }         public string DestFilePath { get; set; }          public event ProgressChangeDelegate OnProgressChanged;         public event Completedelegate OnComplete;     } 

Just run it in separate thread and subscribe for OnProgressChanged event.

like image 197
Anton Semenov Avatar answered Sep 18 '22 23:09

Anton Semenov


I like this solution, because

The copy engine is in the framework

public delegate void IntDelegate(int Int);  public static event IntDelegate FileCopyProgress; public static void CopyFileWithProgress(string source, string destination) {     var webClient = new WebClient();     webClient.DownloadProgressChanged += DownloadProgress;     webClient.DownloadFileAsync(new Uri(source), destination); }  private static void DownloadProgress(object sender, DownloadProgressChangedEventArgs e) {     if(FileCopyProgress != null)         FileCopyProgress(e.ProgressPercentage); } 

UNC Paths

This should work with UNC paths as long as the permissions are set up. If not, you will get this error, in which case, I vote for the authenticated request user route.

System.UnauthorizedAccessException: Access to the path '\testws01\c$\foo' is denied.

ASP.NET is not authorized to access the requested resource. Consider granting access rights to the resource to the ASP.NET request identity. ASP.NET has a base process identity (typically {MACHINE}\ASPNET on IIS 5 or Network Service on IIS 6 and IIS 7, and the configured application pool identity on IIS 7.5) that is used if the application is not impersonating. If the application is impersonating via <identity impersonate="true"/>, the identity will be the anonymous user (typically IUSR_MACHINENAME) or the authenticated request user.

like image 35
toddmo Avatar answered Sep 18 '22 23:09

toddmo