asynchronous文件复制/在C#中移动

在C#中进行文件复制/asynchronous移动的正确方法是什么?

asynchronous编程的思想是允许调用线程(假设它是线程池线程)在asynchronousIO完成时返回到线程池以用于其他任务。 调用上下文被塞进一个数据结构,一个或多个IO完成线程监视等待完成的调用。 当IO完成时,完成线程调用返回到恢复调用上下文的线程池。 这样,而不是100个线程阻塞,只有完成线程和几个线程池线程大部分闲置。

我能想到的最好的是:

public async Task CopyFileAsync(string sourcePath, string destinationPath) { using (Stream source = File.Open(sourcePath)) { using(Stream destination = File.Create(destinationPath)) { await source.CopyToAsync(destination); } } } 

虽然我没有做过广泛的性能testing。 我有点担心,因为如果这么简单,它已经在核心库中了。

等待我在幕后描述的事情。 如果你想知道它是如何工作的,那么可能有助于理解Jeff Richter的AsyncEnumerator。 他们可能不完全一致,但思路非常接近。 如果您从“asynchronous”方法查看调用堆栈,您将看到MoveNext。

就移动而言,如果它真的是“移动”而不是复制,那么就不需要是asynchronous的,而是删除。 移动是对文件表的快速primefaces操作。 它只能这样工作,但是如果你不想把文件移动到不同的分区。

下面是一个asynchronous文件复制方法,它给出了我们正在读取和写入的操作系统提示,以便它可以预读取数据并准备好写入:

 public static async Task CopyFileAsync(string sourceFile, string destinationFile) { using (var sourceStream = new FileStream(sourceFile, FileMode.Open, FileAccess.Read, FileShare.Read, 4096, FileOptions.Asynchronous | FileOptions.SequentialScan)) using (var destinationStream = new FileStream(destinationFile, FileMode.CreateNew, FileAccess.Write, FileShare.None, 4096, FileOptions.Asynchronous | FileOptions.SequentialScan)) await sourceStream.CopyToAsync(destinationStream); } 

您也可以尝试使用缓冲区大小。 这是4096字节。

我稍微增加了@DrewNoakes的代码(性能和取消):

  public static async Task CopyFileAsync(string sourceFile, string destinationFile, CancellationToken cancellationToken) { var fileOptions = FileOptions.Asynchronous | FileOptions.SequentialScan; var bufferSize = 4096; using (var sourceStream = new FileStream(sourceFile, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize, fileOptions)) using (var destinationStream = new FileStream(destinationFile, FileMode.CreateNew, FileAccess.Write, FileShare.None, bufferSize, fileOptions)) await sourceStream.CopyToAsync(destinationStream, bufferSize, cancellationToken) .ConfigureAwait(continueOnCapturedContext: false); } 

您可以使用asynchronous委托

 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 } } 

你可以这样称呼它:

 AsyncFileCopier.AsynFileCopy("abc.txt", "xyz.txt"); 

这个链接告诉你asyn编码的不同技术

你可以这样做,因为这篇文章build议:

 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); 

虽然在某些情况下你想避免Task.RunTask.Run(() => File.Move(source, dest)将会工作,值得考虑,因为当一个文件被简单地移动到同一个磁盘/卷,这是一个几乎是即时的操作,因为头文件被改变,但文件内容不移动,各种“纯”的asynchronous方法总是复制stream,即使不需要这样做,结果在实践中可能会相当慢一些。

AFAIK,没有高级别的asynchronousAPI来复制文件。 但是,您可以使用Stream.BeginRead/EndReadStream.BeginWrite/EndWrite API构build自己的API来完成该任务。 或者,您可以使用BeginInvoke/EndInvoke方法,如答案中所述,但是您必须记住,它们不会是非阻塞的asynchronousI / O。 他们只是在一个单独的线程上执行任务。

正确的方法来复制:使用一个单独的线程。

以下是你如何做(同步):

 //.. [code] doFileCopy(); // .. [more code] 

以下是如何asynchronous执行的:

 // .. [code] new System.Threading.Thread(doFileCopy).Start(); // .. [more code] 

这是一种非常天真的做事方式。 做得好,解决scheme将包括一些事件/委托方法来报告文件副本的状态,并通知重要的事件,如失败,完成等。

欢呼声,jrh

我build议使用.Net编程语言提供的文件复制IOfunction在任何情况下都是asynchronous的。 在我的程序中使用它来移动小文件后,似乎在实际文件复制完成之前开始执行后续指令。 我担心可执行文件给Windows任务做复制,然后立即返回执行下一个指令 – 不等待Windows完成。 这迫使我在构buildwhile循环之后立即执行复制,直到我可以确认复制完成。