What is the correct way to do file copy/move asynchronously in C#?
A:
The correct way to copy: use a separate thread.
Here's how you might be doing it (synchronously):
//.. [code]
doFileCopy();
// .. [more code]
Here's how to do it asynchronously:
// .. [code]
new System.Threading.Thread(doFileCopy).Start();
// .. [more code]
This is a very naive way to do things. Done well, the solution would include some event/delegate method to report the status of the file copy, and notify important events like failure, completion etc.
cheers, jrh
Here Be Wolves
2009-05-19 13:20:41
+2
A:
You can use asynchronous delegates
public class AsyncFileCopier
{
public delegate void FileCopyDelegate(string sourceFile, string destFile);
public static void AsynFileCopy(string sourceFile, string destFile)
{
FileCopyDelegate del = new FileCopyDelegate(FileCopy);
IAsyncResult result = del.BeginInvoke(sourceFile, destFile, CallBackAfterFileCopied, null);
}
public static void FileCopy(string sourceFile, string destFile)
{
// Code to copy the file
}
public static void CallBackAfterFileCopied(IAsyncResult result)
{
// Code to be run after file copy is done
}
}
You can call it as:
AsyncFileCopier.AsynFileCopy("abc.txt", "xyz.txt");
This link tells you the different techniques of asyn coding
Rashmi Pandit
2009-05-19 13:34:48
+1
A:
You can do it as this article suggested:
public static void CopyStreamToStream(
Stream source, Stream destination,
Action<Stream, Stream, Exception> completed)
{
byte[] buffer = new byte[0x1000];
AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(null);
Action<Exception> done = e =>
{
if(completed != null) asyncOp.Post(delegate
{
completed(source, destination, e);
}, null);
};
AsyncCallback rc = null;
rc = readResult =>
{
try
{
int read = source.EndRead(readResult);
if(read > 0)
{
destination.BeginWrite(buffer, 0, read, writeResult =>
{
try
{
destination.EndWrite(writeResult);
source.BeginRead(
buffer, 0, buffer.Length, rc, null);
}
catch(Exception exc) { done(exc); }
}, null);
}
else done(null);
}
catch(Exception exc) { done(exc); }
};
source.BeginRead(buffer, 0, buffer.Length, rc, null);
pablito
2009-05-19 13:42:58
A:
You could use a Backgroundworker to do it.
Here's a Windows forms sample (credit goes to "nobugz" on the msdn forums)
Start a new project and drop a label, button and progressbar on the form. Make sure c:\temp folder exists. Then paste 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();
}
}
}
Matt Frear
2009-07-27 09:44:45