Locked Async CTP file download

  • jueves, 22 de diciembre de 2011 10:36
     
     

    Is there a way I can download a file from FTP using Await?

Todas las respuestas

  • sábado, 24 de diciembre de 2011 14:52
     
     Respondida Tiene código

    It's a simple matter of using the Async methods on WebRequest and Stream.

    Here's a basic implementation, modified from my own async FTP download code:

    public async Task DownloadFileAsync(string ftpPath, string localPath, CancellationToken token = new CancellationToken(), IProgress<uint> progress = null)
    {
      using (var fileStream = File.OpenWrite(localPath))
      {
        var request = (FtpWebRequest)FtpWebRequest.Create(ftpPath);
        request.Method = WebRequestMethods.Ftp.DownloadFile;
        request.KeepAlive = true;
        request.UsePassive = false;
        using (var response = await request.GetResponseAsync().ConfigureAwait(false))
        using (var ftpStream = response.GetResponseStream())
        {
          var buffer = new byte[4096];
          while (true)
          {
            var bytesRead = await ftpStream.ReadAsync(buffer, 0, buffer.Length).ConfigureAwait(false);
            if (bytesRead == 0)
              break;
            await fileStream.WriteAsync(buffer, 0, bytesRead).ConfigureAwait(false);
            token.ThrowIfCancellationRequested();
            if (progress != null)
              progress.Report((uint)bytesRead);
          }
        }
      }
    }
    
    

            -Steve


    Programming blog: http://nitoprograms.blogspot.com/
      Including my TCP/IP .NET Sockets FAQ
      and How to Implement IDisposable and Finalizers: 3 Easy Rules
    Microsoft Certified Professional Developer

    How to get to Heaven according to the Bible

  • sábado, 31 de diciembre de 2011 18:48
    Moderador
     
     Respuesta propuesta

    Stephen's answer is a good one.  It could also be simplified a bit by using Stream.CopyToAsync, e.g.

    public async Task DownloadFileAsync(string ftpPath, string localPath, CancellationToken cancellationToken = default(CancellationToken))
    {
      using (var fileStream = File.OpenWrite(localPath))
      {
        var request = (FtpWebRequest)FtpWebRequest.Create(ftpPath);
        request.Method = WebRequestMethods.Ftp.DownloadFile;
        request.KeepAlive = true;
        request.UsePassive = false;
        using (var response = await request.GetResponseAsync().ConfigureAwait(false))
        using (var ftpStream = response.GetResponseStream())
        {
            await ftpStream.CopyToAsync(fileStream, cancellationTokenoken).ConfigureAwait(false);
        }
      }
    }

    (Though if you do want to provide progress for the copy operation itself, then you'll need to do something like what Stephen did.)

    Also note that while this wil end up using true async I/O for the reads on the FTP request, File.OpenWrite creates a FileStream that's not configured to use async I/O, so the writes here will be asynchronous via queued ThreadPool work items that do synchronous requests, rather than having the OS use async I/O at that layer.  To change that, you'd need to use one of the FileStream ctors that can be configured for async.