Asynchronous Arquivo Copiar / Mover em C #

votos
47

Qual é a maneira correta de fazer cópia de arquivo / mover de forma assíncrona em C #?

Publicado 19/05/2009 em 14:14
fonte usuário
Em outras línguas...                            


9 respostas

votos
35

A idéia de programação assíncrona é permitir que o segmento de chamada (assumindo que é um thread do pool) para retornar ao pool de threads para uso em alguma outra tarefa enquanto S assíncrona concluída. Sob a capa da chamada é enchido contexto numa estrutura de dados e 1 ou mais fios de conclusão IO monitorar a chamada de espera para a sua execução. Quando IO completa a linha de conclusão chama de volta para um pool de threads restaurar o contexto de chamada. Dessa forma, em vez de 100 threads bloqueiam há apenas as threads de conclusão e alguns threads do pool sentados principalmente ocioso.

O melhor que posso dar é:

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

Eu não fiz testes extensivos perf sobre isso embora. Estou um pouco preocupado porque se fosse assim tão simples, ele já estaria nas bibliotecas do núcleo.

aguardam faz o que eu estou descrevendo nos bastidores. Se você quiser ter uma idéia geral de como ele funciona, provavelmente ajudaria a entender AsyncEnumerator de Jeff Richter. Eles podem não ser completamente a mesma linha para linha, mas as idéias são realmente muito próximos. Se você nunca olhar para uma pilha de chamadas a partir de um método "assíncrono", você verá MoveNext nele.

Tanto quanto movimento vai ele não precisa ser assíncrona se é realmente um "Move" e não uma cópia, em seguida, apagar. Movimento é uma operação atômica rápido contra a tabela de arquivo. Ele só funciona dessa forma que se você não tentar mover o arquivo para uma partição diferente.

Respondeu 10/05/2013 em 03:22
fonte usuário

votos
16

Aqui está um método de cópia de arquivo assíncrona que dá as dicas OS que estamos lendo e escrevendo sequencialmente, de modo que possa pré-buscar dados sobre a leitura e ter as coisas prontas para a gravação:

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

É possível experimentar com o tamanho da memória intermédia, bem. Aqui é que é 4096 bytes.

Respondeu 17/02/2016 em 20:51
fonte usuário

votos
8

Eu tenho melhorado código @DrewNoakes ligeiramente (de desempenho e de cancelamento):

  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);
  }
Respondeu 28/04/2016 em 21:27
fonte usuário

votos
6

Você pode usar delegados assíncronos

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

Você pode chamá-lo como:

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

Esta ligação diz-lhe as diferentes técnicas de codificação asyn

Respondeu 19/05/2009 em 14:34
fonte usuário

votos
5

Você pode fazê-lo como este artigo sugere:

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);
Respondeu 19/05/2009 em 14:42
fonte usuário

votos
4

Embora existam algumas circunstâncias em que você gostaria de evitar Task.Run, Task.Run(() => File.Move(source, dest)vai funcionar. Vale a pena considerar, porque quando um arquivo é simplesmente movido no mesmo disco / volume, é uma operação quase instantânea, como os cabeçalhos são alteradas, mas o conteúdo do arquivo não são movidos. Os vários métodos assíncronos "puros" copiar invariavelmente o fluxo, mesmo quando não há necessidade de fazer isso, e como resultado pode ser um pouco mais lento na prática.

Respondeu 04/08/2016 em 01:55
fonte usuário

votos
2

AFAIK, não há alto nível assíncrono API para copiar um arquivo. No entanto, você pode construir sua própria API para realizar essa tarefa usando Stream.BeginRead/EndReade Stream.BeginWrite/EndWriteAPIs. Alternativamente, você pode usar BeginInvoke/EndInvokemétodo como mencionado nas respostas aqui, mas você tem que manter em mente que eles não vão ser não bloqueio assíncrono I / O. Eles simplesmente executar a tarefa em um segmento separado.

Respondeu 02/09/2011 em 23:22
fonte usuário

votos
-1

A maneira correta de copiar: usar um segmento separado.

Veja como você pode estar fazendo isso (síncrona):

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

Aqui está como fazê-lo de forma assíncrona:

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

Esta é uma maneira muito ingênuo para fazer as coisas. bem feito, a solução seria incluir algum método de evento / delegado para relatar o status da cópia de arquivo, e notificar eventos importantes, como a falha, a conclusão etc.

aplausos, JRH

Respondeu 19/05/2009 em 14:20
fonte usuário

votos
-2

Gostaria de sugerir que o arquivo função Copiar IO, disponível nas linguagens de programação .Net, é assíncrona, em qualquer caso. Após usá-lo dentro do meu programa para mover arquivos pequenos, parece que as instruções subseqüentes começam a executar antes da cópia de arquivo real está terminado. Estou Gussing que o executável do Windows dá a tarefa de fazer a cópia e, em seguida, retorna imediatamente para executar a próxima instrução - não esperando para Windows para terminar. Isso me obriga a construir laços while logo após a chamada para copiar que executará até que eu possa confirmar a cópia for concluída.

Respondeu 30/07/2012 em 15:47
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more