views:

6108

answers:

5

I've created a copy utility in c# (.NET 2.0 Framework) that copies files, directories and recursive sub directories etc. The program has a GUI that shows the current file being copied, the current file number (sequence), the total number of files to be copied and the percentage completed for the copy operations. There is also a progress bar, that is based on current file / total files.

My problem is related to copying large files. I've been unable to find a way to indicate the total copy progress of a large file (using my current class structure that utilitzes FileInfo.CopyTo method). As a workaround I've separated the file copy operations and GUI display to their own threads and set up a visual cue to show that work is being done. At least the user is aware that the program isn't frozen and is still copying files.

It would be nicer to be able to show the progress based on the total number of bytes or have some type of event that fires from the FileInfo.CopyTo method that indicates the total number of bytes copied from the current file.

I'm aware of the FileInfo.Length property, so I'm sure there is a way MacGuyver my own event that is based on this and have a handler on the GUI side of things reading the updates (maybe based on checking the FileInfo.Length property of the destination object using some type of timer?).

Does anyone know of a way to do this that I'm overlooking. If I can avoid it, I'd rather not rewrite my class to copy bytes through a stream and track it that way (though I'm thinking I might be stuck with going that route).

Thanks In Advance

PS - I'm stuck with the .NET 2.0 framework for now, so any solution that requires features available in >= 3.0 only are not an option for me.

PPS - I'm open to solutions in any .NET language variety, not only c#.

+15  A: 

The FileInfo.CopyTo is basically a wrapper around the Win32 API call "CopyFile" in the kernel32.dll. This method does not support progress callback.

However, the CopyFileEx method does, and you can write your own .NET wrapper around it in a few minutes, like it is described here: http://www.pinvoke.net/default.aspx/kernel32.CopyFileEx

Gaspar Nagy
Thanks Gaspar. This option looks like one possible way to tackle the issue. I'll look into it a little more.
Jason Down
For what its worth I have successfully used this approach. In fact I'm pretty sure I literally copied that very code from pinvoke.net. agentidle you could make a nice little class to wrap it instead of dealing with all the parameters.
Brian Ensink
+4  A: 

For the love of God do not implement your own file copy using streams! The Win32 CopyFile API call that Gaspar mentioned is able to take advantage of e.g. DMA, whereas I'd bet dollars to doughnuts that the code Will wrote would not be "smart" enough to do that.

CopyFileEx will treat you right, or you could implement a BackgroundWorker that watches the growing size of the target file and updates a progress bar using that information. The latter method saves you a PInvoke, but the former is probably a bit cleaner in the long run.

Coderer
Watching the target file using by using a FileInfo object and checking the length is another option I have considered. I agree though that using the CopyFileEx approach is probably the best way to go.
Jason Down
A: 

For these sorts of things I have fallen back to Shell32 (or is it ShellUI? I don't know anymore). This gives you a native Windows dialog that users are used to seeing for copying operations. I guess it would replace your already existing dialog so it may not be the right answer for you, but it is useful to remember for those "in a pinch" scenarios.

Microsoft.VisualBasic.FileIO.FileSystem.CopyFile(
    srcPath, 
    dstPath, 
    Microsoft.VisualBasic.FileIO.UIOption.AllDialogs,    
    Microsoft.VisualBasic.FileIO.UICancelOption.ThrowException
);

Yes, you must reference the Microsoft.VisualBasic assembly. I've grown to love this assembly.

cfeduke
The only reason I didn't take this route is that I needed to ensure the user couldn't cancel the copy operation.
Jason Down
A: 

I need to implement my own file copy routine, how can I use DMA etc to make sure it runs atleast as fast (or faster) than windows API?

Why I need to write my own routine for copying is that I need to read a file from a memory card and copy it to multiple drives simultaneously, so if I use windows API I will need to read from card multiple times (slow). Instead I am creating a bunch of threads to read buffers from the card and write them to all destinations in parallel.

Works like a charm but can be faster if it can use DMA etc, can you point me to correct APIs or some other source of information?

(am using C# but can fallback to C++ if needed).

You'll want to direct this to its own question.
cfeduke
A: 

I think the best thing is you implement your own class using Streams because if you let CopyFileEx all the work you will find it lacks some features you could implement. For example, if you use your own streams you can decide the buffer you will use (something very important for the speed) and you can implement your own callback (as you do with CopyFileEx). CopyFileEx does not let you decide this kinda thing. I know the most popular option is CopyFileEx, but I assure you that your program will be just slower. At the same time, another advice, use verification of checksum, whenever you program this kinda app, it will let you know if there is a corruption of data.

netadictos