<p>Renci.SshNet 的 SftpClient 是 C# 中最稳定、跨平台的纯 .NET SFTP 下载方案,需显式 Connect(),下载大文件应使用 FileStream 避免 OOM,路径统一用 /,认证失败多因方式不匹配,连接异常需检查网络和端口,下载目录需手动递归遍历。</p>

用 Renci.SshNet 下载文件最直接
直接用 Renci.SshNet 库的 SftpClient 是目前 C# 里最稳定、文档最全的 SFTP 下载方案。它不依赖 OpenSSH 或系统命令,纯 .NET 实现,.NET Framework 4.5+ 和 .NET Core / .NET 5+ 都支持。
安装 NuGet 包:Renci.SshNet(注意不是 Renci.SshNet.Async,那个已弃用)。
关键点:
-
SftpClient必须显式调用Connect(),否则会抛SshConnectionException - 下载大文件时别用
DownloadFile(string, Stream)直接写到MemoryStream,容易 OOM;应传入FileStream或带缓冲的Stream - 路径分隔符统一用
/,即使服务器是 Windows SFTP(如 Bitvise),SFTP 协议本身强制使用 POSIX 路径格式
处理常见错误:AuthenticationFailedException 和 NoRouteToHostException
AuthenticationFailedException 多半不是密码错,而是认证方式不匹配。SFTP 服务器可能只允许 PublicKey,但你代码默认走 PasswordConnectionInfo。
解决办法:
- 确认服务器支持的认证方式(查日志或联系运维),再选对应
ConnectionInfo子类:PasswordConnectionInfo、PrivateKeyConnectionInfo或KeyboardInteractiveConnectionInfo -
NoRouteToHostException表示连不上 IP:Port,检查防火墙、端口(默认 22)、DNS 解析,以及是否误把 FTP 端口(21)当 SFTP 用 - 连接超时默认 30 秒,可设
Timeout = TimeSpan.FromSeconds(10)缩短诊断时间
下载单个文件的最小可靠代码片段
以下代码能跑通,且覆盖了资源释放和异常路径:
using (var client = new SftpClient(host, username, password))
{
try
{
client.Connect();
using (var fileStream = File.Create(@"C:\temp\downloaded.txt"))
{
client.DownloadFile("/remote/path/file.txt", fileStream);
}
}
catch (SftpPathNotFoundException)
{
// 远程路径不存在
}
catch (SshAuthenticationException)
{
// 认证失败
}
finally
{
if (client.IsConnected) client.Disconnect();
}
}注意:DownloadFile 内部已做流复制和缓冲(默认 4KB),不用自己包装 BufferedStream;但若需进度回调,得手动读取 OpenRead() 返回的 SftpFileStream。
下载多个文件或整个目录要自己遍历
SftpClient 没有内置 DownloadDirectory 方法。必须先 ListDirectory,再递归处理每个 SftpFile。
要点:
-
SftpFile的IsDirectory属性才是判断依据,别信扩展名或斜杠 - 远程路径要用
"/" + file.Name拼接,不能用Path.Combine(Windows 反斜杠会破坏路径) - 本地目标路径创建目录要用
Directory.CreateDirectory,File.Create不会自动建父目录 - 并发下载多个文件时,每个
SftpClient实例必须独立创建——该类不是线程安全的
实际项目里,如果要下几百个文件,建议加限流(比如最多 3 个并发 SftpClient),否则容易触发服务器连接数限制或丢包重传。









