This is an old revision of the document!
Recursively download directory tree with custom error handling
The simplest way to download a directory tree is by using Session.GetFiles
, providing path to a root of the tree as a source. This way a batch operation however stops on any error by default.
The following two approaches show how to override the default behaviour.
Advertisement
Handling Session.QueryReceived event
You can choose how an error is processed by handling Session.QueryReceived
event. This feature is available only in the latest beta release.
This example shows a basic implementation that outputs any errors encountered and continues.
C# Example
session.QueryReceived += (sender, e) => { Console.WriteLine("Error: {0}", e); e.Continue(); }; session.Open(sessionOptions); session.GetFiles("/home/user/*", @"d:\download\").Check();
VB.NET Example
AddHandler session.QueryReceived, Sub(sender As Object, e As QueryReceivedEventArgs) Console.WriteLine("Error: {0}", e.Message) e.Continue() End Sub session.Open(sessionOptions) session.GetFiles("/home/user/*", "d:\download\").Check()
Advertisement
PowerShell Example
$session.add_QueryReceived( { Write-Host "Error: $($_.Message)" $_.Continue() } ) $session.Open($sessionOptions) $session.GetFiles("/home/user/*", "d:\download\").Check()
Upload
The same mechanism can be used for uploads with Session.PutFiles
or synchronization with Session.SynchronizeDirectories
.
Explicit Implementation of a File Tree Download
In case you need even more control over a download process, you can implement walking of a directory tree explicitly and handle each file individually, as you need.
This example shows a basic implementation that outputs any errors encountered and continues.
C# Example
using System; using System.Collections.Generic; using System.IO; using WinSCP; class Example { public static int Main() { try { // Setup session options SessionOptions sessionOptions = new SessionOptions { Protocol = Protocol.Sftp, HostName = "example.com", UserName = "user", Password = "mypassword", SshHostKeyFingerprint = "ssh-rsa 2048 xx:xx:xx:xx:xx:xx:xx:xx..." }; string localPath = @"d:\backup"; string remotePath = "/home/user"; using (Session session = new Session()) { // Connect session.Open(sessionOptions); // Enumerate files and directories to download IEnumerable<RemoteFileInfo> fileInfos = session.EnumerateRemoteFiles( remotePath, null, EnumerationOptions.EnumerateDirectories | EnumerationOptions.AllDirectories); foreach (RemoteFileInfo fileInfo in fileInfos) { string localFilePath = session.TranslateRemotePathToLocal( fileInfo.FullName, remotePath, localPath); if (fileInfo.IsDirectory) { // Create local subdirectory, if it does not exist yet if (!Directory.Exists(localFilePath)) { Directory.CreateDirectory(localFilePath); } } else { Console.WriteLine("Downloading file {0}...", fileInfo.FullName); // Download file TransferOperationResult transferResult = session.GetFiles( session.EscapeFileMask(fileInfo.FullName), localFilePath); // Did the download succeeded? if (!transferResult.IsSuccess) { // Print error (but continue with other files) Console.WriteLine( "Error downloading file {0}: {1}", fileInfo.FullName, transferResult.Failures[0].Message); } } } } return 0; } catch (Exception e) { Console.WriteLine("Error: {0}", e); return 1; } } }
Advertisement
PowerShell Example
param ( # Use Generate Session URL function to obtain a value for -sessionUrl parameter. [Parameter(Mandatory = $True)] $sessionUrl = "sftp://user:mypassword;fingerprint=ssh-rsa-xx-xx-xx@example.com/", [Parameter(Mandatory = $True)] $remotePath, [Parameter(Mandatory = $True)] $localPath ) try { # Load WinSCP .NET assembly Add-Type -Path "WinSCPnet.dll" # Setup session options from URL $sessionOptions = New-Object WinSCP.SessionOptions $sessionOptions.ParseUrl($sessionUrl) $session = New-Object WinSCP.Session $session.SessionLogPath = "session.log" try { # Connect $session.Open($sessionOptions) # Enumerate files and directories to download $fileInfos = $session.EnumerateRemoteFiles( $remotePath, $Null, ([WinSCP.EnumerationOptions]::EnumerateDirectories -bor [WinSCP.EnumerationOptions]::AllDirectories)) foreach ($fileInfo in $fileInfos) { $localFilePath = $session.TranslateRemotePathToLocal($fileInfo.FullName, $remotePath, $localPath) if ($fileInfo.IsDirectory) { # Create local subdirectory, if it does not exist yet if (!(Test-Path $localFilePath)) { New-Item $localFilePath -ItemType directory | Out-Null } } else { Write-Host "Downloading file $($fileInfo.FullName)..." # Download file $transferResult = $session.GetFiles( $session.EscapeFileMask($fileInfo.FullName), $localFilePath) # Did the download succeeded? if (!$transferResult.IsSuccess) { # Print error (but continue with other files) Write-Host ( "Error downloading file $($fileInfo.FullName): " + "$($transferResult.Failures[0].Message)") } } } } finally { # Disconnect, clean up $session.Dispose() } exit 0 } catch { Write-Host "Error: $($_.Exception.Message)" exit 1 }
Advertisement
Upload
For an example of walking a local tree to upload files individually, see Recursively move files in directory tree to/from SFTP/FTP server while preserving source directory structure.
The upload example calls OperationResultBase.Check
, so it aborts on any error. Just replace the call with OperationResultBase.IsSuccess
test as this example does. See Capturing Results of Operations