如何提升Windows PowerShell下SFTP文件拉取的性能?
PowerShell SFTP批量下载脚本优化方案
问题分析
你当前的脚本通过Transferetto模块串行下载220个10-14KB的小文件耗时近15分钟,核心瓶颈在于串行处理带来的重复连接开销——每个小文件传输都要经历单独的会话握手、等待确认,叠加起来拖慢了整体效率。
具体优化方法
1. 启用并行下载(最显著提升效率)
串行下载的握手等待是最大耗时点,改用并行处理可以把总耗时压缩到数分钟内。根据你的PowerShell版本选择方案:
方案1:PowerShell 7+ 用ForEach-Object -Parallel
Set-ExecutionPolicy RemoteSigned -Scope Process -Force Import-Module Transferetto # 配置基础参数 $server = '124.77.98.211' $username = 'FTDD' $password = 'RRGGTIjhh78' $localBasePath = "\\data\file\" # 先获取文件列表 $sftpConn = Connect-SFTP -Server $server -Username $username -Password $password $fileList = Get-SFTPList -SftpClient $sftpConn -Path '/FTDD' Disconnect-SFTP -SftpClient $sftpConn # 并行下载,控制并发数避免服务器过载 $fileList | ForEach-Object -Parallel { Import-Module Transferetto $conn = Connect-SFTP -Server $using:server -Username $using:username -Password $using:password Receive-SFTPFile -SftpClient $conn -RemotePath $_.FullName -LocalPath "$using:localBasePath$($_.Name)" Write-Host "完成下载:$($_.FullName)" Disconnect-SFTP -SftpClient $conn } -ThrottleLimit 10 # 并发数可根据网络和服务器负载调整,建议5-15之间
方案2:PowerShell 5.x 用Start-Job
Set-ExecutionPolicy RemoteSigned -Scope Process -Force Import-Module Transferetto # 配置基础参数 $server = '124.77.98.211' $username = 'FTDD' $password = 'RRGGTIjhh78' $localBasePath = "\\data\file\" # 先获取文件列表 $sftpConn = Connect-SFTP -Server $server -Username $username -Password $password $fileList = Get-SFTPList -SftpClient $sftpConn -Path '/FTDD' Disconnect-SFTP -SftpClient $sftpConn # 创建批量下载任务 $downloadJobs = $fileList | ForEach-Object { Start-Job -ScriptBlock { param($file, $server, $user, $pwd, $localPath) Import-Module Transferetto $conn = Connect-SFTP -Server $server -Username $user -Password $pwd Receive-SFTPFile -SftpClient $conn -RemotePath $file.FullName -LocalPath "$localPath$($file.Name)" Write-Host "完成下载:$($file.FullName)" Disconnect-SFTP -SftpClient $conn } -ArgumentList $_, $server, $username, $password, $localBasePath } # 等待所有任务完成并清理 Wait-Job $downloadJobs | Out-Null Receive-Job $downloadJobs | Out-Null Remove-Job $downloadJobs
2. 调整Transferetto传输参数
- 增大缓冲区:给
Receive-SFTPFile添加-BufferSize参数,减少IO交互次数,比如设置为64KB:Receive-SFTPFile -SftpClient $SftpClient -RemotePath $File.FullName -LocalPath "\\data\file\$($File.Name)" -BufferSize 65536 - 启用传输压缩:连接SFTP时开启压缩,减少小文件的传输字节数:
$SftpClient = Connect-SFTP -Server '124.77.98.211' -Username 'FTDD' -Password 'RRGGTIjhh78' -Compression $true
3. 跳过已存在的文件
下载前检查本地文件是否存在且大小一致,避免重复下载浪费时间:
foreach ($File in $List) { $localFilePath = "\\data\file\$($File.Name)" if (-not (Test-Path $localFilePath) -or (Get-Item $localFilePath).Length -ne $File.Length) { Receive-SFTPFile -SftpClient $SftpClient -RemotePath $File.FullName -LocalPath $localFilePath Write-Host "已下载:$($File.FullName)" } else { Write-Host "跳过已存在文件:$($File.Name)" } }
4. 更换更高效的SFTP模块
Transferetto基于SSH.NET封装,部分场景下原生使用WinSCP模块(支持多线程批量下载)效率更高:
Set-ExecutionPolicy RemoteSigned -Scope Process -Force # 先安装WinSCP模块:Install-Module -Name WinSCP $sessionOpts = New-Object WinSCP.SessionOptions -Property @{ Protocol = [WinSCP.Protocol]::Sftp HostName = '124.77.98.211' UserName = 'FTDD' Password = 'RRGGTIjhh78' } $session = New-Object WinSCP.Session $session.Open($sessionOpts) # WinSCP默认多线程批量下载,直接拉取目录下所有文件 $session.GetFiles('/FTDD/*', '\\data\file\*').Check() $session.Dispose()
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

