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

C#从S3取MemoryStream通过SFTP发送时遇“无效路径”问题求解

解决无需本地路径直接通过SFTP发送MemoryStream的问题

问题核心原因

你当前代码存在两个关键错误,直接导致了SftpPathNotFoundException:

  1. 关闭FileStream后再调用UploadFile,此时流已不可读;且UploadFile的第二个参数传入了本地临时文件路径,SFTP客户端会误将其当作远程服务器路径,引发无效路径报错。
  2. 完全没必要把S3返回的MemoryStream写入本地临时文件,Renci.SshNet的SftpClient.UploadFile原生支持直接传入任意可读流(包括MemoryStream)。

修正后的SendFile方法

public async Task SendFile(SftpRequest request, CancellationToken cancellationToken = default)
{
    // 使用using自动释放客户端资源,替代手动Dispose
    using var client = new SftpClient(request.Host, request.Port, request.Username, request.Password);
    client.Connect();

    if (!client.IsConnected)
    {
        throw new SftpClientException("SFTP Connection was not complete.");
    }

    // 关键:重置MemoryStream的位置到开头,确保SFTP客户端能读取完整内容
    request.RefundFile.Position = 0;

    // 第二个参数是远程服务器的目标文件路径,需根据服务器实际目录调整
    // 示例:传到远程服务器的"/uploads"目录下,文件名为"refund-file.txt"
    client.UploadFile(request.RefundFile, "/uploads/refund-file.txt");
}

修正要点说明

  • 移除所有本地临时文件相关操作,直接复用S3返回的MemoryStream,节省磁盘IO开销。
  • 必须重置MemoryStream.Position = 0:从S3获取流后,流的读取指针通常停在末尾,不重置会导致上传空文件。
  • UploadFile的第二个参数需传入远程服务器的完整目标路径,而非本地路径。

测试代码修正(笔误修复)

测试方法中存在变量名笔误,将refundFileMock改为s3FileMock:

private SftpRequest MockSftpRequest()
{
    var serverMock = new ServerOptions()
    {
        BaseAddress = "195.144.107.198",
        Username = "demo",
        Password = "password",
    };

    var s3FileMock = new MemoryStream(Encoding.UTF8.GetBytes("This is a mock of the s3 file."));

    SftpRequest request = new SftpRequest(serverMock)
    {
        RefundFile = s3FileMock,
        Port = 22,
    };

    return request;
}

内容的提问来源于stack exchange,提问作者David Leites

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 14:05:37