2015-12-02 22 views
6

Sto cercando di scaricare file in modo asincrono da un server SFTP usando SSH.NET. Se lo faccio in modo sincrono, funziona bene, ma quando lo faccio async, ottengo file vuoti. Questo è il mio codice:Download file asincrono SSH.Net

var port = 22; 
string host = "localhost"; 
string username = "user"; 
string password = "password"; 
string localPath = @"C:\temp"; 

using (var client = new SftpClient(host, port, username, password)) 
{ 
    client.Connect(); 
    var files = client.ListDirectory(""); 

    var tasks = new List<Task>(); 

    foreach (var file in files) 
    {       
     using (var saveFile = File.OpenWrite(localPath + "\\" + file.Name)) 
     { 
      //sftp.DownloadFile(file.FullName,saveFile); <-- This works fine 
      tasks.Add(Task.Factory.FromAsync(client.BeginDownloadFile(file.FullName, saveFile), client.EndDownloadFile)); 
     }       
    } 

    await Task.WhenAll(tasks); 
    client.Disconnect(); 

} 

risposta

7

Perché saveFile è dichiarato in un blocco using, è chiuso subito dopo si avvia il compito, in modo che il download non è possibile completare. In realtà, sono sorpreso che tu non stia ricevendo un'eccezione.

Si potrebbe estrarre il codice per scaricare ad un metodo separato come questo:

var port = 22; 
string host = "localhost"; 
string username = "user"; 
string password = "password"; 
string localPath = @"C:\temp"; 

using (var client = new SftpClient(host, port, username, password)) 
{ 
    client.Connect(); 
    var files = client.ListDirectory(""); 

    var tasks = new List<Task>(); 

    foreach (var file in files) 
    {       
     tasks.Add(DownloadFileAsync(file.FullName, localPath + "\\" + file.Name)); 
    } 

    await Task.WhenAll(tasks); 
    client.Disconnect(); 

} 

... 

async Task DownloadFileAsync(string source, string destination) 
{ 
    using (var saveFile = File.OpenWrite(destination)) 
    { 
     var task = Task.Factory.FromAsync(client.BeginDownloadFile(source, saveFile), client.EndDownloadFile); 
     await task; 
    } 
} 

In questo modo, il file non viene chiuso prima di aver terminato il download.


Guardando il codice sorgente SSH.NET, sembra che la versione asincrona di DownloadFile non utilizza "reale" async IO (tramite porta di completamento IO), ma invece appena eseguito il download in un nuovo thread . Quindi non c'è un reale vantaggio nell'uso di BeginDownloadFile/EndDownloadFile; si potrebbe anche utilizzare DownloadFile in un thread che si crea da soli:

Task DownloadFileAsync(string source, string destination) 
{ 
    return Task.Run(() => 
    { 
     using (var saveFile = File.OpenWrite(destination)) 
     { 
      client.DownloadFile(source, saveFile); 
     } 
    } 
} 
+0

@YuvalItzchakov, fisso, grazie! –

+0

Grazie per la risposta, tuttavia, ho ancora gli stessi file vuoti quando provo questo. Nessuna eccezione neanche. – spersson

+2

@spersson, ho aggiornato la mia risposta. Sembra che non ci sia alcun vantaggio nell'uso di 'BeginDownloadFile', quindi potresti usare la versione sincrona. –