26286 total geeks with 3498 solutions
Recent challengers:
 Welcome, you are an anonymous user! [register] [login] Get a yourname@osix.net email address 

Articles

GEEK

User's box
Username:
Password:

Forgot password?
New account

Shoutbox
MaxMouse
It's Friday... That's good enough for me!
CodeX
non stop lolz here but thats soon to end thanks to uni, surely the rest of the world is going good?
stabat
how things are going guys? Here... boring...
CodeX
I must be going wrong on the password lengths then, as long as it was done on ECB
MaxMouse
lol... the key is in hex (MD5: of the string "doit" without the "'s) and is in lower case. Maybe i should have submitted this as a challenge!

Donate
Donate and help us fund new challenges
Donate!
Due Date: May 31
May Goal: $40.00
Gross: $0.00
Net Balance: $0.00
Left to go: $40.00
Contributors


News Feeds
The Register
Orange customer
clobbered with SIX
FIGURE phone bill
Tipsters exposed
after South
Africa"s national
police force hacked
Samsung flogs slim,
flashy new model:
Protection included
Another Chinese
thing you can see
from space:
Lenovo"s sales
New York cop in
alleged
love-polyhedron
email hack spree
Penguin pays $75m
to settle ebook
price-fixing case
"Leccy car biz
baron Elon Musk:
Thanks for the
$500m, taxpayers...
Apple cored:
Samsung sells 10
million Galaxy S4
in a month
Brit spooks bugged
Edward VIII"s
phones, records
reveal
Virgin Media slides
fat 10Gbps pipes
into Murdoch"s
BSkyB
Slashdot
Ask Slashdot: How
To Determine If a
Video Has Been
Faked?
Curiosity Rewarded:
Florida Teen
Heading to Space
Camp, Not Jail
A Cold Look at Cold
Fusion Claims: Why
E-Cat Looks Like a
Hoax
NVIDIA GeForce GTX
780 Offers 2,304
Cores For $650
French Police End
Missing Persons
Searches, Suggest
Using Facebook
Kim Dotcom Wants
Money From Google,
Twitter For
2-Factor
Authentication
Meet Pidora, the
New Official Fedora
Remix For Raspberry
Pi
Terrorist Murder In
London Could Revive
Snooper"s Charter
One-Time Pad From
Caltech Offers
Uncrackable
Cryptography
First Government
Lawsuit Against a
Patent Troll
Article viewer

Copy Files in C# with a progress bar



Written by:cadey
Published by:cadey
Published on:2009-05-27 16:11:03
Topic:Dot.Net
Search OSI about Dot.Net.More articles by cadey.
 viewed 18665 times send this article printer friendly

Digg this!
    Rate this article :
This seems like a hot topic and so I decided to make my own class to do this simple function. Its got a few extras that may not be needed for your implementation but feel free to rip those out or add more functionality to it :)

Added this as a project.
http://www.osix.net/modules/folder/index.php?tid=33709&action=vf

This is the main class, you can bolt on a GUI or widget by implementing the bellow interface and passing it to the constructor.

1:      /// <summary>
2:      /// Copies a list of files or a directory tree to a destination
3:      ///
4:      /// Support for GUI is implamented by the ICopyFilesDiag interface
5:      /// and passed to the class in the copy() method.
6:      /// </summary>
7:      public class CopyFiles
8:      {
9:  
10:          // Variables
11:          private List<String> files = new List<String>();
12:          private List<String> newFilenames = new List<String>();
13:          private List<ST_CopyFileDetails> filesCopied = new List<ST_CopyFileDetails>();
14:          private Int32 totalFiles = 0;
15:          private Int32 totalFilesCopied = 0;
16:          private String destinationDir = "";
17:          private String sourceDir = "";
18:          private String currentFilename;
19:          private Boolean cancel = false;
20:          private IAsyncResult CopyResult;
21:          private DEL_CopyFiles delCopy;
22:          private ICopyFilesDiag digWindow;
23:  
24:          // Structurs
25:          public struct ST_CopyFileDetails
26:          {
27:  
28:              String OriginalURI;
29:              String NewURI;
30:  
31:              // Constructor
32:              public ST_CopyFileDetails(String FromURI, String ToURI)
33:              {
34:                  OriginalURI = FromURI;
35:                  NewURI = ToURI;
36:              }
37:  
38:          }
39:  
40:          // Enums
41:          // These Enums are used for the windows CopyFileEx function
42:          [Flags]
43:          private enum CopyFileFlags : uint
44:          {
45:              COPY_FILE_FAIL_IF_EXISTS = 0x00000001,
46:              COPY_FILE_RESTARTABLE = 0x00000002,
47:              COPY_FILE_OPEN_SOURCE_FOR_WRITE = 0x00000004,
48:              COPY_FILE_ALLOW_DECRYPTED_DESTINATION = 0x00000008
49:          }
50:          private enum CopyProgressResult : uint
51:          {
52:              PROGRESS_CONTINUE = 0,
53:              PROGRESS_CANCEL = 1,
54:              PROGRESS_STOP = 2,
55:              PROGRESS_QUIET = 3
56:          }
57:          private enum CopyProgressCallbackReason : uint
58:          {
59:              CALLBACK_CHUNK_FINISHED = 0x00000000,
60:              CALLBACK_STREAM_SWITCH = 0x00000001
61:          }
62:  
63:          // Events
64:          public event DEL_copyComplete EV_copyComplete;
65:          public event DEL_copyCanceled EV_copyCanceled;
66:  
67:          // Delegates
68:          private delegate CopyProgressResult CopyProgressRoutine(Int64 TotalFileSize, Int64 TotalBytesTransferred, Int64 StreamSize, Int64 StreamBytesTransferred, UInt32 dwStreamNumber, CopyProgressCallbackReason dwCallbackReason, IntPtr hSourceFile, IntPtr hDestinationFile, IntPtr lpData);
69:          private delegate CopyProgressResult DEL_CopyProgressHandler(Int64 total, Int64 transferred, Int64 streamSize, Int64 StreamByteTrans, UInt32 dwStreamNumber, CopyProgressCallbackReason reason, IntPtr hSourceFile, IntPtr hDestinationFile, IntPtr lpData);
70:          private delegate void DEL_CopyFiles();
71:          private delegate void DEL_ShowDiag(ICopyFilesDiag diag);
72:          private delegate void DEL_HideDiag(ICopyFilesDiag diag);
73:          private delegate void DEL_CopyfilesCallback(IAsyncResult r);
74:  
75:          public delegate void DEL_cancelCopy();
76:          public delegate void DEL_copyComplete();
77:          public delegate void DEL_copyCanceled(List<ST_CopyFileDetails> filescopied);
78:  
79:          // Constructors
80:          public CopyFiles(String source, String destination)
81:          {
82:              //As the directory tree might be large we work out the
83:              //files in the threaded call Copyfiles()
84:              sourceDir = source;
85:              destinationDir = destination;
86:          }
87:          public CopyFiles(List<String> sourceFiles, String destination)
88:          {
89:  
90:              //The sourceDir does not need to be set if the user is supplying a
91:              //list of files.
92:              //
93:              //Example :
94:              // Source Destination
95:              // c:\Temp1\Test.txt c:\DestFolder\Test.txt
96:              // c:\temp2\temp1\test1.txt c:\DestFolder\Test1.txt
97:              // c:\temp3\blah\Test.txt c:\DestFolder\Test (2).txt
98:              //
99:              //This is worked out in CheckFilenames()
100:              files = sourceFiles;
101:              totalFiles = files.Count;
102:              destinationDir = destination;
103:          }
104:  
105:          // Kernal32 Calls
106:          // Unsafe is need to show that we are using
107:          // pointers which are classed as "unsafe" in .net
108:          [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
109:          [return: MarshalAs(UnmanagedType.Bool)]
110:          static extern unsafe bool CopyFileEx(string lpExistingFileName, string lpNewFileName, CopyProgressRoutine lpProgressRoutine, IntPtr lpData, Boolean* pbCancel, CopyFileFlags dwCopyFlags);
111:  
112:          // Methods
113:          private List<String> GetFiles(String sourceDir)
114:          {
115:  
116:              // Variables
117:              List<String> foundFiles = new List<String>();
118:              String[] fileEntries;
119:              String[] subdirEntries;
120:  
121:              //Add root files in this DIR to the list
122:              fileEntries = System.IO.Directory.GetFiles(sourceDir);
123:              foreach (String filename in fileEntries)
124:              {
125:                  foundFiles.Add(filename);
126:              }
127:  
128:              //Loop the DIR's in the current DIR
129:              subdirEntries = System.IO.Directory.GetDirectories(sourceDir);
130:              foreach (string subdir in subdirEntries)
131:              {
132:  
133:                  //Dont open Folder Redirects as this can end up in an infinate loop
134:                  if ((System.IO.File.GetAttributes(subdir) &
135:                       System.IO.FileAttributes.ReparsePoint) !=
136:                       System.IO.FileAttributes.ReparsePoint)
137:                  {
138:                      //Run recursivly to follow this DIR tree
139:                      //adding all the files along the way
140:                      foundFiles.AddRange(GetFiles(subdir));
141:                  }
142:  
143:              }
144:  
145:              return foundFiles;
146:          }
147:          private CopyProgressResult CopyProgressHandler(Int64 total, Int64 transferred, Int64 streamSize, Int64 StreamByteTrans, UInt32 dwStreamNumber, CopyProgressCallbackReason reason, IntPtr hSourceFile, IntPtr hDestinationFile, IntPtr lpData)
148:          {
149:              //Check to see if there is a dialog window to use
150:              if (digWindow != null)
151:              {
152:                  //Are we going to send the update on the correct thread?
153:                  if (digWindow.SynchronizationObject != null && digWindow.SynchronizationObject.InvokeRequired)
154:                  {
155:                      digWindow.SynchronizationObject.Invoke(new CopyProgressRoutine(CopyProgressHandler),
156:                                  new Object[] { total, transferred, streamSize, StreamByteTrans, dwStreamNumber, reason, hSourceFile, hDestinationFile, lpData });
157:                  }
158:                  else
159:                  {
160:                      digWindow.update(totalFiles, totalFilesCopied, total, transferred, currentFilename);
161:                  }
162:  
163:              }
164:              return CopyProgressResult.PROGRESS_CONTINUE;
165:          }
166:          private void ShowDiag(ICopyFilesDiag diag)
167:          {
168:              //Check to see if there is a dialog window to use
169:              if (digWindow != null)
170:              {
171:                  //Are we going to send the update on the correct thread?
172:                  if (digWindow.SynchronizationObject != null && digWindow.SynchronizationObject.InvokeRequired)
173:                  {
174:                      digWindow.SynchronizationObject.Invoke(new DEL_ShowDiag(ShowDiag),
175:                          new Object[] { diag });
176:                  }
177:                  else
178:                  {
179:                      diag.Show();
180:                  }
181:              }
182:          }
183:          private void HideDiag(ICopyFilesDiag diag)
184:          {
185:              //Check to see if there is a dialog window to use
186:              if (digWindow != null)
187:              {
188:                  //Are we going to send the update on the correct thread?
189:                  if (digWindow.SynchronizationObject != null && digWindow.SynchronizationObject.InvokeRequired)
190:                  {
191:                      digWindow.SynchronizationObject.Invoke(new DEL_HideDiag(HideDiag),
192:                          new Object[] { diag });
193:                  }
194:                  else
195:                  {
196:                      diag.Hide();
197:                      cancel = false;
198:                  }
199:              }
200:          }
201:          private void CancelCopy()
202:          {
203:              cancel = true;
204:              OnCopyCanceled();
205:          }
206:          private void Copyfiles()
207:          {
208:  
209:              Int32 index = 0;
210:  
211:              //Show the dialog box and hook into its cancel event if
212:              //a dialog box has been given
213:              if (digWindow != null)
214:              {
215:                  digWindow.EN_cancelCopy += CancelCopy;
216:                  ShowDiag(digWindow);
217:              }
218:  
219:              //If we have been a sourceDIR then find all the files to copy
220:              if (sourceDir != "")
221:              {
222:                  files = GetFiles(sourceDir);
223:              }
224:              else
225:              {
226:                  CheckFilenames();
227:              }
228:              totalFiles = files.Count;
229:  
230:              //Loop each file and copy it.
231:              foreach (String filename in files.ToArray())
232:              {
233:                  String[] filepath;
234:                  String tempFilepath;
235:                  String tempDirPath = "";
236:  
237:                  //If we have a source directory, strip that off the filename
238:                  if (sourceDir != "")
239:                  {
240:                      tempFilepath = filename;
241:                      tempFilepath = tempFilepath.Replace(sourceDir, "");
242:                      tempFilepath = System.IO.Path.Combine(destinationDir, tempFilepath);
243:                  }
244:                  //otherwise strip off all the folder path
245:                  else
246:                  {
247:                      tempFilepath = System.IO.Path.Combine(destinationDir, newFilenames[index]);
248:                  }
249:  
250:                  //Save the new DIR path and check the DIR exsits,
251:                  //if it does not then create it so the files can copy
252:                  filepath = tempFilepath.Split('\\');
253:                  for (int i = 0; i < filepath.Length - 1; i++)
254:                  {
255:                      tempDirPath += filepath[i] + "\\";
256:                  }
257:                  if (!System.IO.Directory.Exists(tempDirPath))
258:                  {
259:                      System.IO.Directory.CreateDirectory(tempDirPath);
260:                  }
261:  
262:                  //Have be been told to stop copying files
263:                  if (cancel)
264:                  {
265:                      break;
266:                  }
267:  
268:                  //Set the file thats just about to get copied
269:                  currentFilename = filename;
270:  
271:                  //Unsafe is need to show that we are using
272:                  //pointers which are classed as "unsafe" in .net
273:                  //
274:                  //CopyFileEx needs a pointer to the cancel boolean, it checks this
275:                  //constantly as the file copies, if it gets set to true it will stop
276:                  //
277:                  //Note :
278:                  // fixed is used to get the memory pointer of our local boolean.
279:                  // It is then saved in a pointer (declared like a normal type but
280:                  // with a * at the end)
281:                  //
282:                  // We can then pass this memory address to the Kernal32 call.
283:                  unsafe
284:                  {
285:                      fixed (Boolean* cancelp = &cancel)
286:                      {
287:                          CopyFileEx(filename, tempFilepath, new CopyProgressRoutine(this.CopyProgressHandler), IntPtr.Zero, cancelp, 0);
288:                      }
289:                  }
290:                  filesCopied.Add(new ST_CopyFileDetails(filename, tempFilepath));
291:                  totalFilesCopied += 1;
292:                  index += 1;
293:  
294:              }
295:  
296:          }
297:          private void OnCopyComplete()
298:          {
299:              if (EV_copyComplete != null)
300:              {
301:                  EV_copyComplete();
302:              }
303:          }
304:          private void OnCopyCanceled()
305:          {
306:              if (EV_copyCanceled != null)
307:              {
308:                  EV_copyCanceled(filesCopied);
309:              }
310:          }
311:          private void CheckFilenames()
312:          {
313:              // Variables
314:              String[] fileNames = new String[files.Count];
315:              List<String> tempFileNameArr;
316:              Int32 index = 0;
317:              Int32 innerIndex = 0;
318:              Int32 filenameIndex = 0;
319:              Int32 filenameNumber = 0;
320:  
321:              //Load filenames into an array
322:              foreach (String tempFileName in files)
323:              {
324:                  fileNames[index] = System.IO.Path.GetFileName(tempFileName);
325:                  index += 1;
326:              }
327:  
328:              //Loop each filename in the array
329:              index = 0;
330:              foreach (String originalFilename in fileNames)
331:              {
332:  
333:                  //See if this filename is repeated in the list
334:                  innerIndex = 0;
335:                  filenameNumber = 2;
336:                  foreach (String dupeFilename in fileNames)
337:                  {
338:                      //dont compair the same index!
339:                      if (innerIndex != index)
340:                      {
341:  
342:                          if (originalFilename == dupeFilename)
343:                          {
344:                              //insert the duplicate number into the new filename e.g (2) and clear
345:                              //the current name.
346:                              tempFileNameArr = new List<String>(fileNames[innerIndex].Split('.'));
347:                              tempFileNameArr.Insert(tempFileNameArr.Count - 1, "[*REMOVEME*] (" + filenameNumber + ")");
348:                              fileNames[innerIndex] = "";
349:  
350:                              //Rebuild the new filename
351:                              filenameIndex = 0;
352:                              foreach (String newFilename in tempFileNameArr)
353:                              {
354:  
355:                                  //put a dot before the file extension
356:                                  if (filenameIndex == tempFileNameArr.Count - 1)
357:                                  { fileNames[innerIndex] += "."; }
358:  
359:                                  //append the new filename
360:                                  fileNames[innerIndex] += newFilename.Replace("[*REMOVEME*]", "");
361:  
362:                                  //only add a . if its not the injected portion e.g (2)
363:                                  if ((filenameIndex < tempFileNameArr.Count - 3 && newFilename.StartsWith("[*REMOVEME*]") == false))
364:                                  { fileNames[innerIndex] += "."; }
365:  
366:                                  filenameIndex += 1;
367:                              }
368:  
369:                              //Trim any trailing .'s
370:                              fileNames[innerIndex].TrimEnd(new Char[] { '.' });
371:                              filenameNumber += 1;
372:                          }
373:                      }
374:                      innerIndex += 1;
375:                  }
376:                  index += 1;
377:  
378:              }
379:  
380:              //Update the list of new filenames.
381:              newFilenames = new List<String>(fileNames);
382:  
383:          }
384:  
385:          //Copy the files
386:          public void Copy()
387:          {
388:              Copyfiles();
389:          }
390:          public void CopyAsync(ICopyFilesDiag diag)
391:          {
392:              digWindow = diag;
393:  
394:              if (digWindow != null && digWindow.SynchronizationObject == null)
395:              {
396:                  throw new Exception("Dialog window sent with no SynchronizationObject");
397:              }
398:  
399:              delCopy = new DEL_CopyFiles(Copyfiles);
400:              CopyResult = delCopy.BeginInvoke(CopyfilesCallback, null);
401:          }
402:  
403:          // Async Callbacks
404:          private void CopyfilesCallback(IAsyncResult r)
405:          {
406:              //Kill off the thread as its finished.
407:              delCopy.EndInvoke(CopyResult);
408:              HideDiag(digWindow);
409:              OnCopyComplete();
410:          }
411:  
412:      }
413:  


Here is the interface that should be placed with the class.

1:      //The interface for the Dialog the CopyFiles class uses.
2:      public interface ICopyFilesDiag
3:      {
4:          //needed to sync the CopyClass update events with the dialog thread
5:          System.ComponentModel.ISynchronizeInvoke SynchronizationObject { get; set; }
6:  
7:          //This event should fire when you want to cancel the copy
8:          event CopyFiles.DEL_cancelCopy EN_cancelCopy;
9:  
10:          //This is how the CopyClass will send your dialog information about
11:          //the transfer
12:          void update(Int32 totalFiles, Int32 copiedFiles, Int64 totalBytes, Int64 copiedBytes, String currentFilename);
13:          void Show();
14:          void Hide();
15:  
16:      }
17:  


Finally here is an implentation of the interface, this is a simple form that opens up and whows the prgress of the copy. You will need to add two lables, two progress bars and a button to get it to work.

1:  public partial class DIA_CopyFiles : Form, ICopyFilesDiag
2:      {
3:  
4:          // Properties
5:          public System.ComponentModel.ISynchronizeInvoke SynchronizationObject { get; set; }
6:  
7:          // Constructors
8:          public DIA_CopyFiles()
9:          {
10:              InitializeComponent();
11:          }
12:  
13:          // Methods
14:          public void update(Int32 totalFiles, Int32 copiedFiles, Int64 totalBytes, Int64 copiedBytes, String currentFilename)
15:          {
16:              Prog_TotalFiles.Maximum = totalFiles;
17:              Prog_TotalFiles.Value = copiedFiles;
18:              Prog_CurrentFile.Maximum = 100;
19:              if (totalBytes != 0)
20:              {
21:                  Prog_CurrentFile.Value = Convert.ToInt32((100f / (totalBytes / 1024f)) * (copiedBytes / 1024f));
22:              }
23:  
24:              Lab_TotalFiles.Text = "Total files (" + copiedFiles + "/" + totalFiles + ")";
25:              Lab_CurrentFile.Text = currentFilename;
26:          }
27:          private void But_Cancel_Click(object sender, EventArgs e)
28:          {
29:              RaiseCancel();
30:          }
31:          private void DIA_CopyFiles_Closed(object sender, System.EventArgs e)
32:          {
33:              RaiseCancel();
34:          }
35:          private void RaiseCancel()
36:          {
37:              if (EN_cancelCopy != null)
38:              {
39:                  EN_cancelCopy();
40:              }
41:          }
42:  
43:          //Events
44:          public event CopyFiles.DEL_cancelCopy EN_cancelCopy;
45:  
46:  
47:      }
48:  

Did you like this article? There are hundreds more.

Comments:
Anonymous
2009-06-16 03:03:53
This is great but the synchronous copy doesn't show progress. Can that be done with this wrapper?
cadey
2009-06-17 20:32:33
Erm, well a synchronous copy will not return a progress because its on the main thread. You will need to call the CopyAsync to show the progress.

Can you say why you need a synchronous copy and show a progress. May be its a "how do I know its finished" problem your having? – this is solved by the events :)
IB3
2009-06-18 04:57:37
Well cadey - you are correct. I'd like to be able to kick off the copying of files, do other stuff, and if that other stuff finishes fist then wait for the copy process to complete.

I am a total moron when it comes to events from asnyc processes. I've been reading stuff and testing stuff and for some reason just can't get my head around it.

Would you be willing to toss in the check for "all files copied" or something in this sample? If not - I totally understand. I've registered my name as "IB3" because I feel like I'm three years old. Nobody likes three year olds!!! :o)
IB3
2009-06-18 05:12:15
I'm using the sample from CodeProject and trying to tell from "TestCopy" when the files are complete. I should ask this question there instead huh?
Anonymous
2009-06-19 19:09:45
If you want to know when a copy is complete in a-sync simply handle the OnCopyComplete event? that will inform you when all the files have been copied?

If you’re using the sync copy then when it gets to the next line of code the copy has finished?
Anonymous
2011-06-28 15:32:32
wow stunning proclamation but you have an error in line 135, anyway incredible work!
Anonymously add a comment: (or register here)
(registration is really fast and we send you no spam)
BB Code is enabled.
Captcha Number:


Blogs: (People who have posted blogs on this subject..)
bb
ASP.NET RadioButton GroupName when inside a Repeater on Sun 10th Jun 8am
I was thankful on finding this nugget of code, which makes the groupname work out when slamming in radiobuttons in an asp.net repeater. http://www.codeguru.com/csharp/csharp/cs _controls/custom/article.php/c12371/


     
Your Ad Here
 
Copyright Open Source Institute, 2006