SSH.Net 异步文件下载

问题描述 投票:0回答:2

我正在尝试使用 SSH.NET 从 SFTP 服务器异步下载文件。如果我同步执行,它工作正常,但是当我异步执行时,我会得到空文件。这是我的代码:

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

}
c# asynchronous sftp ssh.net
2个回答
16
投票

由于

saveFile
是在
using
块中声明的,因此在启动任务后它会立即关闭,因此下载无法完成。事实上,我很惊讶你没有得到例外。

您可以提取代码以下载到单独的方法,如下所示:

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

这样,在完成下载文件之前,文件不会关闭。


查看SSH.NET源代码,看起来异步版本的

DownloadFile
并没有使用“真正的”异步IO(使用IO完成端口),而只是在新线程中执行下载。所以使用
BeginDownloadFile
/
EndDownloadFile
并没有真正的优势;您也可以在自己创建的线程中使用
DownloadFile

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

0
投票

他们终于在不久前更新了方法,但没有按照最初的要求添加显式的

DownloadFileAsync
。您可以在这里查看讨论:

https://github.com/sshnet/SSH.NET/pull/819

提供的解决方案是:

public static class SftpClientExtensions
{
    public static async Task DownloadFileAsync(this SftpClient sftpClient, string path, Stream output, CancellationToken cancellationToken)
    {
        using (Stream remoteStream = await sftpClient.OpenAsync(path, FileMode.Open, FileAccess.Read, cancellationToken).ConfigureAwait(false))
        {
            await remoteStream.CopyToAsync(output, 81920, cancellationToken).ConfigureAwait(false);
        }
    }

    public static async Task UploadFileAsync(this SftpClient sftpClient, Stream input, string path, FileMode createMode, CancellationToken cancellationToken)
    {
        using (Stream remoteStream = await sftpClient.OpenAsync(path, createMode, FileAccess.Write, cancellationToken).ConfigureAwait(false))
        {
            await input.CopyToAsync(remoteStream, 81920, cancellationToken).ConfigureAwait(false);
        }
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.