|
this is very good small application, but needs to edit some codes
Thank you
|
|
|
|
|
Thanks Neil for this code! It is very educative.
Copy from folder was not working due to code on line 250 in CopyFiles.cs.
I replaced lines 249 and 250 with
tempFilepath = Path.GetFileName(filename);
That fixes illegal path that would cause program to fail.
|
|
|
|
|
Hi,
This is a great article and it works great. But only with files. I tried the suggested fix (Adding "\\" at the end of the path) below with no result. I also created a new list just for folders and uncommented the below line of code:
<pre
uncomment="" the="" next="" line="" to="" copy="" file="" tree.
="" copyfiles.copyfiles="" temp="
" new="" copyfiles.copyfiles("c:\\copy="" test="" folder",="" "c:\\test");
<="" pre="">
So my questions are
1) How do I copy folders over
2) And I think this would be more useful, how do you copy both folders and files at the same time?
Thank you everyone in advance!
|
|
|
|
|
please how can i show copying progress form as a dialog due to prevent the user from accessing the form1?
|
|
|
|
|
In line no 251 in class CopyFiles.cs file
tempFilepath = System.IO.Path.Combine(destinationDir, tempFilepath);
The above code is unable to combine path as it usually works.
I replaced the code with the below :
tempFilepath = (destinationDir + "\\" + tempFilepath);
and it's working fine..
Don't know why. Can anyone give me chance to see answer for this.
|
|
|
|
|
Someone can explain how disable form1 until async process is finished?
modified 16-Jan-16 8:53am.
|
|
|
|
|
how to do this progress thing in c# console while copy and paste a file..please tell anyone
|
|
|
|
|
For copying individual files your code is working fine.
But if we want to copy directories with the same subfolder structure, your code is not working as it is copying all the files from subdirectories also to the single destination directory.
Any help on this?
|
|
|
|
|
Hallo Forum,
I´ve got a question, can i copy a file and rename it?
Regards
ElSpeedy
|
|
|
|
|
Hello, i am trying to make an usercontrol that show only the two progress bar, when i try to execute it from another form everythig is fine but i can't make an event that notifies me when the copy is complete. any idea???
|
|
|
|
|
You actually don't need to make the code unsafe. Ref will suffice. For myself the code was more than I required so I made simpler. Here is a basic version and example on the same form. It raises events on the main form to show progress.
using System;
namespace Controls.Common
{
public class FileCopiedEventArgs
{
public FileCopiedEventArgs(string file) { File = file; }
public FileCopiedEventArgs(string file, Exception exception)
{
File = file;
Error = exception;
}
public String File {get; private set;}
public Exception Error { get; private set; }
public bool Cancel;
}
public class FileCopyCompleteEventArgs
{
public FileCopyCompleteEventArgs(bool cancel, Exception lastError) { Cancel = cancel; LastError = lastError;}
public bool Cancel { get; private set; }
public Exception LastError { get; private set; }
}
public class CopyFiles
{
private List<String> files = new List<String>();
private readonly List<String> newFilenames = new List<String>();
private Int32 _totalFiles = 0;
private Int32 _totalFilesCopied = 0;
private readonly String _destinationDir = "";
private readonly String _sourceDir = "";
private String _currentFilename;
private Boolean _cancel = false;
private Thread _copyThread;
private const int ERROR_REQUEST_ABORTED = 1235;
public event FileCopyCompleteEventHandler CopyComplete;
public event FileCopiedEventHandler FileCopied;
public delegate void FileCopiedEventHandler(object sender, FileCopiedEventArgs e);
public delegate void FileCopyCompleteEventHandler(object sender, FileCopyCompleteEventArgs e);
public CopyFiles(String source, String destination)
{
_sourceDir = source;
_destinationDir = destination;
}
public CopyFiles(List<String> sourceFiles, String destination)
{
files = sourceFiles;
_totalFiles = files.Count;
_destinationDir = destination;
}
public CopyFiles(List<String> sourceFiles, List<String> destFiles)
{
if (sourceFiles.Count != destFiles.Count) throw new Exception("Array Length Mismatch");
files = sourceFiles;
_totalFiles = files.Count;
newFilenames = destFiles;
}
public delegate void CopyProgressHandlerDelegate(Int32 totalFiles, Int32 copiedFiles, Int64 totalBytes, Int64 copiedBytes, String currentFilename);
public event CopyProgressHandlerDelegate ProgressEvent;
private List<String> GetFiles(String sourceDir)
{
String[] fileEntries;
String[] subdirEntries;
fileEntries = System.IO.Directory.GetFiles(sourceDir);
List<String> foundFiles = fileEntries.ToList();
subdirEntries = System.IO.Directory.GetDirectories(sourceDir);
foreach (string subdir in subdirEntries)
{
if ((System.IO.File.GetAttributes(subdir) &
System.IO.FileAttributes.ReparsePoint) !=
System.IO.FileAttributes.ReparsePoint)
{
foundFiles.AddRange(GetFiles(subdir));
}
}
return foundFiles;
}
private NativeMethods.CopyProgressResult CopyProgressHandler(Int64 total, Int64 transferred, Int64 streamSize, Int64 streamByteTrans, UInt32 dwStreamNumber, NativeMethods.CopyProgressCallbackReason reason, IntPtr hSourceFile, IntPtr hDestinationFile, IntPtr lpData)
{
if (ProgressEvent != null)
ProgressEvent(_totalFiles, _totalFilesCopied, total, transferred, _currentFilename);
return _cancel ? NativeMethods.CopyProgressResult.PROGRESS_CANCEL : NativeMethods.CopyProgressResult.PROGRESS_CONTINUE;
}
public void CancelCopy()
{
_cancel = true;
}
private void Copyfiles()
{
try
{
Exception lastError = null;
Int32 index = 0;
if (!String.IsNullOrEmpty(_sourceDir))
files = GetFiles(_sourceDir);
_totalFiles = files.Count;
foreach (String filename in files.ToArray())
{
String tempFilepath;
if (!String.IsNullOrEmpty(_sourceDir))
{
tempFilepath = filename;
tempFilepath = tempFilepath.Replace(_sourceDir, "").TrimStart(Path.DirectorySeparatorChar);
tempFilepath = System.IO.Path.Combine(_destinationDir, tempFilepath);
}
else
{
tempFilepath = String.IsNullOrEmpty(_destinationDir) ? newFilenames[index] : System.IO.Path.Combine(_destinationDir, newFilenames[index]);
}
string tempDirPath = Path.GetDirectoryName(tempFilepath);
if (!System.IO.Directory.Exists(tempDirPath))
System.IO.Directory.CreateDirectory(tempDirPath);
if (_cancel)
break;
_currentFilename = filename;
bool result = NativeMethods.CopyFileEx(filename, tempFilepath, new NativeMethods.CopyProgressDelegate(this.CopyProgressHandler), IntPtr.Zero, ref _cancel, 0);
_totalFilesCopied++;
if (!result)
{
if (Marshal.GetLastWin32Error() != ERROR_REQUEST_ABORTED)
lastError = new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error());
else
_cancel = true;
OnFileCopied(filename, lastError);
}
else
OnFileCopied(filename);
index++;
}
OnCopyComplete(lastError);
}
catch (Exception ex)
{
OnCopyComplete(ex);
}
}
protected void OnCopyComplete(Exception error)
{
if (CopyComplete != null)
{
CopyComplete(this, new FileCopyCompleteEventArgs(_cancel, error));
}
}
protected void OnFileCopied(string fileName)
{
if (FileCopied != null)
{
FileCopiedEventArgs eventArgs = new FileCopiedEventArgs(fileName);
FileCopied(this, eventArgs);
_cancel = eventArgs.Cancel;
}
}
protected void OnFileCopied(string fileName, Exception exception)
{
if (FileCopied == null) return;
FileCopiedEventArgs eventArgs = new FileCopiedEventArgs(fileName, exception);
eventArgs.Cancel = _cancel;
FileCopied(this, eventArgs);
_cancel = eventArgs.Cancel;
}
public void Copy()
{
_copyThread = new Thread(new ThreadStart(Copyfiles)) {Name = "CopyThread"};
_copyThread.Start();
}
}
}
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace Controls.Common
{
public partial class frmCopyFiles : Form
{
private CopyFiles f;
public frmCopyFiles(List<string> sourceFiles, List<string> destFiles)
{
InitializeComponent();
f = new CopyFiles(sourceFiles, destFiles);
f.ProgressEvent += new CopyFiles.CopyProgressHandlerDelegate(update);
f.CopyComplete += new CopyFiles.FileCopyCompleteEventHandler(f_CopyComplete);
f.FileCopied += new CopyFiles.FileCopiedEventHandler(f_FileCopied);
}
void f_FileCopied(object sender, FileCopiedEventArgs e)
{
if (e.Error != null)
e.Cancel = true;
}
void f_CopyComplete(object sender, FileCopyCompleteEventArgs e)
{
if (InvokeRequired)
{
Invoke(new CopyFiles.FileCopyCompleteEventHandler(f_CopyComplete), new object[] {sender, e});
return;
}
if (e.Cancel || e.LastError != null)
DialogResult = System.Windows.Forms.DialogResult.Cancel;
if (e.LastError != null)
{
btnCancel.Text = "OK";
MessageBox.Show(e.LastError.Message);
}
else
{
DialogResult = System.Windows.Forms.DialogResult.OK;
Close();
}
}
public frmCopyFiles(string source, string dest)
{
InitializeComponent();
f = new CopyFiles(source, dest);
f.ProgressEvent += new CopyFiles.CopyProgressHandlerDelegate(update);
f.CopyComplete += new CopyFiles.FileCopyCompleteEventHandler(f_CopyComplete);
f.FileCopied += new CopyFiles.FileCopiedEventHandler(f_FileCopied);
}
public frmCopyFiles(List<string> sourceFiles, string destDirectory)
{
InitializeComponent();
f = new CopyFiles(sourceFiles, destDirectory);
f.ProgressEvent += new CopyFiles.CopyProgressHandlerDelegate(update);
f.CopyComplete += new CopyFiles.FileCopyCompleteEventHandler(f_CopyComplete);
f.FileCopied += new CopyFiles.FileCopiedEventHandler(f_FileCopied);
}
private void update(Int32 totalFiles, Int32 copiedFiles, Int64 totalBytes, Int64 copiedBytes, String currentFilename)
{
if (InvokeRequired)
{
BeginInvoke(new CopyFiles.CopyProgressHandlerDelegate(update),new object[] {totalFiles, copiedFiles, totalBytes, copiedBytes, currentFilename});
return;
}
Prog_TotalFiles.Maximum = totalFiles;
Prog_TotalFiles.Value = copiedFiles;
Prog_CurrentFile.Maximum = 100;
if (totalBytes != 0)
{
Prog_CurrentFile.Value = Convert.ToInt32((100f / (totalBytes / 1024f)) * (copiedBytes / 1024f));
}
Lab_TotalFiles.Text = "Total files (" + copiedFiles + "/" + totalFiles + ")";
Lab_CurrentFile.Text = currentFilename;
}
private void But_Cancel_Click(object sender, EventArgs e)
{
if (btnCancel.Text == "OK")
Close();
else
{
f.CancelCopy();
btnCancel.Enabled = false;
}
}
private void frmCopyFiles_Closed(object sender, System.EventArgs e)
{
f.CancelCopy();
}
private void frmCopyFiles_Shown(object sender, EventArgs e)
{
f.Copy();
}
}
}
internal static class NativeMethods
{
public const int FSCTL_SET_COMPRESSION = 0x9C040;
public const short COMPRESSION_FORMAT_DEFAULT = 1;
public const int HWND_BROADCAST = 0xFFFF;
[Flags]
public enum CopyFileFlags : uint
{
COPY_FILE_FAIL_IF_EXISTS = 0x00000001,
COPY_FILE_RESTARTABLE = 0x00000002,
COPY_FILE_OPEN_SOURCE_FOR_WRITE = 0x00000004,
COPY_FILE_ALLOW_DECRYPTED_DESTINATION = 0x00000008
}
public enum CopyProgressResult : uint
{
PROGRESS_CONTINUE = 0,
PROGRESS_CANCEL = 1,
PROGRESS_STOP = 2,
PROGRESS_QUIET = 3
}
public enum CopyProgressCallbackReason : uint
{
CALLBACK_CHUNK_FINISHED = 0x00000000,
CALLBACK_STREAM_SWITCH = 0x00000001
}
public delegate CopyProgressResult CopyProgressDelegate(Int64 TotalFileSize, Int64 TotalBytesTransferred, Int64 StreamSize, Int64 StreamBytesTransferred, UInt32 dwStreamNumber, CopyProgressCallbackReason dwCallbackReason, IntPtr hSourceFile, IntPtr hDestinationFile, IntPtr lpData);
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CopyFileEx(string existingFileName, string newFileName, CopyProgressDelegate lpProgressRoutine, IntPtr lpData, ref bool pbCancel, CopyFileFlags dwCopyFlags);
}
|
|
|
|
|
How could I change this code to make it copy or move depending on a Boolean variable argument.
|
|
|
|
|
hello
I now copy file, open source file, the path in the textbox inside, open the target file, path in another textbox inside, with the progress bar shows, percentage, copy completed many display, now code to write bad, consult, hope comprehensive point! thank you
|
|
|
|
|
|
Folder copy to folder, display duplicate progress bar and copy percentage, can achieve at ordinary times copy show the effect of the same
|
|
|
|
|
Hello!
Thank you very much for this great article. I have a little question: I have to copy a folder tree containing some empty folders, running your code it doesn't copy empty folders, I need that folders to be created anyway, how can I do this?
Thanks
|
|
|
|
|
Change the code to automatically create the directory on the target.
Then, regardless if there are files in the source directory or not, the target directory has been created.
That is: TargetDirectoryCreated + NoFilesInSourceDirectory = EmpyTargetDirectory;
ASPX ~ Apple Simply Performs eXcellently
|
|
|
|
|
Excellent article.
Is it possible to implement such a task?
There is a text file txt with a list of file paths of the form:
C: \ Dir \ file1.exe
C: \ Dir \ My Folder \ file2.exe
C: \ Book \ file3.doc
You must copy these files to the specified directory paths in preserving the folder structure, for example, must be copied into a directory on drive D: \ copy of the list so that you are:
D: \ copy of the list \ C \ Dir \ file1.exe
D: \ copy of the list \ C \ Dir \ My Folder \ file2.exe
D: \ copy of the list \ C \ Book \ file3.doc
Thanks in advance for your help!
|
|
|
|
|
|
I am a bit new to this so bear with me. When I use a normal file copy method and a file is locked, I get an IO exception. However, when I run this code with files that I know are locked, no errors are thrown. So I am a bit baffled as to why since I don't see any error handling for that scenario.
I would really like to be able to pop up an error or write to a log if a IO lock or authentication error occured.
Thanks.
|
|
|
|
|
Hi there
I have seen the new fix for the copy folder, but when it reaches the end, I get the following error
System.ArgumentOutOfRangeException was unhandled by user code
Message="Value of '984' is not valid for 'Value'. 'Value' should be between 'minimum' and 'maximum'.\r\nParameter name: Value"
Source="System.Windows.Forms"
ParamName="Value"
StackTrace:
at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous)
at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args)
at CopyFiles.CopyFiles.CopyProgressHandler(Int64 total, Int64 transferred, Int64 streamSize, Int64 StreamByteTrans, UInt32 dwStreamNumber, CopyProgressCallbackReason reason, IntPtr hSourceFile, IntPtr hDestinationFile, IntPtr lpData) in C:\Users\nrasool\Desktop\Nadeem\Project\DatixWebInstaller\DatixWebInstaller\CopyFiles.cs:line 165
at CopyFiles.CopyFiles.CopyFileEx(String lpExistingFileName, String lpNewFileName, CopyProgressRoutine lpProgressRoutine, IntPtr lpData, Boolean* pbCancel, CopyFileFlags dwCopyFlags)
at CopyFiles.CopyFiles.Copyfiles() in C:\Users\nrasool\Desktop\Nadeem\Project\DatixWebInstaller\DatixWebInstaller\CopyFiles.cs:line 298
at System.Runtime.Remoting.Messaging.StackBuilderSink._PrivateProcessMessage(IntPtr md, Object[] args, Object server, Int32 methodPtr, Boolean fExecuteInContext, Object[]& outArgs)
at System.Runtime.Remoting.Messaging.StackBuilderSink.PrivateProcessMessage(RuntimeMethodHandle md, Object[] args, Object server, Int32 methodPtr, Boolean fExecuteInContext, Object[]& outArgs)
at System.Runtime.Remoting.Messaging.StackBuilderSink.AsyncProcessMessage(IMessage msg, IMessageSink replySink)
InnerException:
It seems to have a problem in CopyFile.cs with the following line:
digWindow.SynchronizationObject.Invoke(new CopyProgressRoutine(CopyProgressHandler),
new Object[] { total, transferred, streamSize, StreamByteTrans, dwStreamNumber, reason, hSourceFile, hDestinationFile, lpData });
Please could someone help on this
Many thanks
Kind Regards
|
|
|
|
|
Hi,
That is to do with the progress bar by the looks of things, to be hones I didnt really test is on any files bigger than about 400 meg. put a brake point over the line in the copy files dialog which is being called by the update event, you should see the code where it works out the max value of the progress bar. that should help you resolve that issue.
|
|
|
|
|
Nice.
A little more detail (to add to the source code) would be more helpful though.
Me, I'm dishonest. And a dishonest man you can always trust to be dishonest. Honestly. It's the honest ones you want to watch out for...
|
|
|
|
|
|
Hello, First of all Thank you very much for writing this great article.
I run the sample and it works like a charm!
However, I would like to know one more thing that is to copy an entire tree of the foler that's specified, meaning copying test1, test2, test3, test4 folders and put files that belong to those subfolder when being copied.
I've looked at CopyFiles.cs file and tried to see I could modify to achieve this. I gave up after looking at it for 2 mins.
If you could give me a clue as to how, I would appreciate it so much! 
|
|
|
|
|
Hiya,
the code should already copy subfolders in the folder you specified to stat copying, its only if you supply it with a list of files it will only copy the ones you tell it to. Give me an example of how you are using the class if giving it jsut a folder path does not solve your problem?
|
|
|
|
|