C#从S3取MemoryStream通过SFTP发送时遇“无效路径”问题求解
解决无需本地路径直接通过SFTP发送MemoryStream的问题
问题核心原因
你当前代码存在两个关键错误,直接导致了SftpPathNotFoundException:
- 关闭
FileStream后再调用UploadFile,此时流已不可读;且UploadFile的第二个参数传入了本地临时文件路径,SFTP客户端会误将其当作远程服务器路径,引发无效路径报错。 - 完全没必要把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
相关产品推荐
相关产品推荐

