You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用SSH.NET异步下载SFTP文件转MemoryStream时无法返回结果

问题分析与解决方案

核心错误

你代码里的stream = (MemoryStream)result;是完全错误的——result是IAsyncResult类型的异步操作结果对象,根本不是MemoryStream。你一开始创建的stream已经被写入了下载的内容,不需要转换,只需要正确处理它。

另外你用了过时的APM(Begin/End)异步模式,SSH.NET已经提供了更贴合C# async/await语法的异步方法,没必要自己轮询等待。

修正后的代码

public class SshServices
{
    public async Task<MemoryStream> DownloadFile(CancellationToken cancellationToken)
    {
        // 不要用静态的SftpClient,避免线程安全问题,方法内部创建并自动释放
        using var sftpClient = new SftpClient("test.rebex.net", "demo", "password");
        
        // 使用传入的取消令牌,而非固定的None
        await sftpClient.ConnectAsync(cancellationToken);

        if (!sftpClient.IsConnected)
        {
            throw new InvalidOperationException("无法连接到SFTP服务器");
        }

        var serverFilePath = "/readme.txt"; // SFTP服务器路径标准用正斜杠
        var stream = new MemoryStream();
        
        // 使用官方异步下载方法,直接await等待完成
        await sftpClient.DownloadFileAsync(serverFilePath, stream, cancellationToken);
        
        // 重置流的读取位置到开头,否则调用方读取时会从流末尾开始
        stream.Position = 0;
        
        await sftpClient.DisconnectAsync(cancellationToken);
        return stream;
    }
}

关键修改点

  • 移除静态s_sftpClient,改用using声明自动管理客户端资源,避免多线程环境下的安全问题
  • 替换APM异步模式为DownloadFileAsync,直接用await等待下载完成,无需手动轮询
  • 下载完成后将MemoryStream的Position设为0,确保调用方可以正常读取流内容
  • 全程使用传入的CancellationToken,支持操作取消
  • 统一SFTP路径为正斜杠格式,适配绝大多数SFTP服务器的路径规范

内容的提问来源于stack exchange,提问作者Yasim Yasin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 04:40:11