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).
Making your own file copy logic by using 2 streams as presented by Gal is a viable option but its not recommended solely because there is a deeply intergrated windows operation which is optimized in reliability, security and performance named CopyFileEx.
that said, in the following article: http://msdn.microsoft.com/en-us/magazine/cc163851.aspx they do exactly what you want, but ofcourse you have to use CopyFileEx
Good luck
** EDIT ** (fixed my answer, badly witten)
I like this solution, because
The copy engine is in the framework
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.
Here's an optimized solution that utilizes .NET extensions and a double-buffer for better performance. A new overload of CopyTo is added to FileInfo with an Action that indicates progress only when it has changed.
This sample implementation in WPF with a progress bar named progressBar1 that performs the copy operation in the background.
Here's an example for a Console Application
To use, create a new file, such as FileInfoExtensions.cs and add this code:
The double buffer works by using one thread to read and one thread to write, so the max speed is dictated only by the slower of the two. Two buffers are used (a double buffer), ensuring that the read and write threads are never using the same buffer at the same time.
Example: the code reads into buffer 1, then when the read completes, a write operation starts writing the contents of buffer 1. Without waiting finish writing, the buffer is swapped to buffer 2 and data is read into buffer 2 while buffer 1 is still being written. Once the read completes in buffer 2, it waits for write to complete on buffer 1, starts writing buffer 2, and the process repeats. Essentially, 1 thread is always reading, and one is always writing.
WriteAsync uses overlapped I/O, which utilizes I/O completion ports, which rely on hardware to perform asynchronous operations rather than threads, making this very efficient. TLDR: I lied about there being 2 threads, but the concept is the same.
you can use Dispatcher to update your ProgressBar .
You can copy parts of the file stream from each file, and update after each "chunk" you update. Thus it will be more continuous - you can also easily calculate the relative size of the current "chunk" you are copying relative to the total stream size in order to show the correct percentage done.
You need something like this:
Just run it in separate thread and subscribe for
OnProgressChanged
event.