如何使用winscpnet.dll并发上载文件

时间:2017-10-19 04:21:01

标签: powershell concurrency sftp winscp winscp-net

如何使用winscpnet.dll并发上传文件。我想设置winscp.exe实例,它们可以使用脚本或c#同时运行到x个winscp.exe实例。

其他线程已经在下面的链接中提到了文档,但该代码将查看远程服务器并使用session.GetFiles同时下载x session中的所有文件 https://winscp.net/eng/docs/library_example_parallel_transfers#powershell

我希望做类似但希望使用session.PutFiles从目录上传文件。

winscpnet.dll代码中内置了一个函数,它将枚举远程目录,但没有任何东西可以用于相反的操作。循环遍历本地目录并启动winscp.exe的五个实例,完成后直到所有文件都完成,session.Putfiles传输。

这一点很重要的原因是,将它们一次上传到远程sftp服务器所需要的时间要长得多。

2 个答案:

答案 0 :(得分:1)

  • WinSCP .NET程序集中没有用于枚举本地文件的API,因为它与远程连接无关。

    在PowerShell中实际上是一个API,Get-ChildItem

  • 除此之外,代码与下载代码几乎相同(除了明显的差异,例如使用Session.PutFiles而不是Session.GetFiles)。

您引用的文章现在包含upload in parallel connections over SFTP protocol in C#的完整代码。

答案 1 :(得分:1)

如果你仍然需要它,我们就去吧。

#Powershell script to upload files from a local dire 
param ( 
$sessionUrl = "sftp://tester:password;fingerprint=ssh-rsa 2048 ba:5d:a4:1b:0a:73:30:cf:90:dd:e3:ef:6c:9e:1d:94@localhost", 
$remotePath = "/", 
$localPath = "C:\Users\your\test\upload", 
$batches = 3 
) 

#Upload data to local Rebex Tiny SFTP 

try 
{ 
    # Load WinSCP .NET assembly 
    $dllPath = (Join-Path $PSScriptRoot "WinSCPnet.dll") 
    # Load WinSCP .NET assembly 
    Add-Type -Path $dllPath 

    $started = Get-Date 

    # Build list of local files and sort them from larges to smallest 
    $files = Get-ChildItem $localPath | Sort-Object Length -Descending 

    # Calculate total size of all files 
    $total = ($files | Measure-Object -Property Length -Sum).Sum 

    # And batch size 
    $batch = [int]($total / $batches) 

    Write-Host ("Will upload {0} files totaling {1} bytes in {2} parallel batches, {3} bytes on average in each" -f $files.Count, $total, $batches, $batch) 

    $start = 0 
    $sum = 0 
    $no = 0 

    for ($i = 0; $i -lt $files.Count; $i++) 
    { 
        $sum += $files[$i].Length 

        # Found enough files for the next batch 
        if (($sum -ge $batch) -or ($i -eq $files.Count - 1)) 
        { 
            Write-Host ("Starting batch {0} to upload {1} files totaling {2}" -f $no, ($i - $start + 1), $sum) 

            $fileList = $files[$start..$i] -join ";" 

            # Start the background job for the batch 
            Start-Job -Name "Batch $no" -ArgumentList $dllPath, $sessionUrl, $localPath, $remotePath, $no, $fileList { 
                param ( 
                    [Parameter(Position = 0)] 
                    $dllPath, 
                    [Parameter(Position = 1)] 
                    $sessionUrl, 
                    [Parameter(Position = 2)] 
                    $localPath, 
                    [Parameter(Position = 3)] 
                    $remotePath, 
                    [Parameter(Position = 4)] 
                    $no, 
                    [Parameter(Position = 5)] 
                    $fileList 
                ) 

                try 
                { 
                    Write-Host ("Starting batch {0}" -f $no) 

                    # Load WinSCP .NET assembly. 
                    # Need to use an absolute path as the Job is started from user's documents folder. 
                    Add-Type -Path $dllPath 

                    # Setup session options 
                    $sessionOptions = New-Object WinSCP.SessionOptions 
                    $sessionOptions.ParseUrl($sessionUrl) 

                    try 
                    { 
                        Write-Host ("Connecting batch {0}..." -f $no) 
                        $session = New-Object WinSCP.Session 

                        $session.Open($sessionOptions) 

                        $files = $fileList -split ";" 

                        # Upload the files selected for this batch 
                        foreach ($file in $files) 
                        { 
                            $localFilePath = "$localPath\$file" 
                            $remoteFilePath = "$remotePath/$file" 
                            Write-Host "Uploading $localFilePath to $remoteFilePath in $no" 

                            $session.PutFiles($session.EscapeFileMask($localFilePath), $remoteFilePath).Check() 
                        } 
                    } 
                    finally 
                    { 
                        # Disconnect, clean up 
                        $session.Dispose() 
                    } 

                    Write-Host ("Batch {0} done" -f $no) 
                } 
                catch [Exception] 
                { 
                    Write-Host $_.Exception.Message 
                    exit 1 
                } 
            } | Out-Null 

            # Reset for the next batch 
            $no++ 
            $sum = 0 
            $start = $i + 1 
        } 
    } 

    Write-Host "Waiting for batches to complete" 
    Get-Job | Receive-Job -Wait 

    Write-Host "Done" 

    $ended = Get-Date 
    Write-Host ("Took {0}" -f (New-TimeSpan -Start $started -End $ended)) 

    exit 0 
} 
catch [Exception] 
{ 
    Write-Host $_.Exception.Message 
    exit 1 
}