Differences

This shows you the differences between the selected revisions of the page.

library_example_recursive_download_custom_error_handling 2016-03-31 library_example_recursive_download_custom_error_handling 2022-06-16 (current)
Line 1: Line 1:
====== Recursively download directory tree with custom error handling ====== ====== Recursively download directory tree with custom error handling ======
-The simplest way to download a directory tree is by using ''[[library_session_getfiles|Session.GetFiles]]'', providing path to a root of the tree as a source. This way a batch operation however stops on any error. If you need to use a custom error handling, for example to ignore any error and just continue, you need to implement walking the tree explicitly.+The simplest way to download a directory tree is by using ''[[library_session_getfiles|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. 
 + 
 +Particularly the first approach with ''[[library_session_queryreceived|Session.QueryReceived]]'' event is relevant for other batch operations as well, including ''[[library_session_putfiles|Session.PutFiles]]'' and ''[[library_session_synchronizedirectories|Session.SynchronizeDirectories]]''. 
 + 
 +===== [[queryreceived]] Handling Session.QueryReceived event ===== 
 + 
 +You can choose how an error is processed by handling ''[[library_session_queryreceived|Session.QueryReceived]]'' event.
This example shows a basic implementation that outputs any errors encountered and continues. This example shows a basic implementation that outputs any errors encountered and continues.
-===== In the Beta Version ===== +==== C# Example ==== 
-In the latest beta version, you can simplify the implementation by using ''[[library_session_enumerateremotefiles|Session.EnumerateRemoteFiles]]''.·&beta+ 
 +<code csharp> 
 +session.QueryReceived += (sender, e) =
 +
 +    Console.WriteLine("Error: {0}", e); 
 +    e.Continue(); 
 +}; 
 + 
 +session.GetFiles("/home/user/*", @"d:\download\").Check(); 
 +</code> 
 + 
 +==== VB.NET Example ==== 
 + 
 +<code vbnet> 
 +AddHandler session.QueryReceived, 
 +   Sub(sender As Object, e As QueryReceivedEventArgs) 
 +        Console.WriteLine("Error: {0}", e.Message) 
 +        e.Continue() 
 +    End Sub 
 + 
 +session.GetFiles("/home/user/*", "d:\download\").Check() 
 +</code> 
 + 
 +==== [[event_powershell]] PowerShell Example ==== 
 + 
 +<code powershell> 
 +$session.add_QueryReceived( {  
 +    Write-Host "Error: $($_.Message)" 
 +    $_.Continue() 
 +} ) 
 + 
 +$session.GetFiles("/home/user/*", "d:\download\").Check() 
 +</code> 
 + 
 +==== Upload ==== 
 + 
 +The same mechanism can be used for uploads with ''[[library_session_putfiles|Session.PutFiles]]'' or synchronization with ''[[library_session_synchronizedirectories|Session.SynchronizeDirectories]]&#039;'. 
 + 
 + 
 +===== [[tree_download]] 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 ==== ==== C# Example ====
Line 28: Line 79:
                UserName = "user",                 UserName = "user",
                Password = "mypassword",                 Password = "mypassword",
-                SshHostKeyFingerprint = "ssh-rsa 2048 xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx"+                SshHostKeyFingerprint = "ssh-rsa 2048 xxxxxxxxxxx..."
            };             };
Line 40: Line 91:
                // Enumerate files and directories to download                 // Enumerate files and directories to download
 +                var opts = WinSCP.EnumerationOptions.EnumerateDirectories |
 +                          WinSCP.EnumerationOptions.AllDirectories;
                IEnumerable<RemoteFileInfo> fileInfos =                 IEnumerable<RemoteFileInfo> fileInfos =
-                    session.EnumerateRemoteFiles( +                    session.EnumerateRemoteFiles(remotePath, null, opts);
-························remotePath, null, +
-                       EnumerationOptions.EnumerateDirectories | EnumerationOptions.AllDirectories);+
                foreach (RemoteFileInfo fileInfo in fileInfos)                 foreach (RemoteFileInfo fileInfo in fileInfos)
                {                 {
-                    string localFilePath = session.TranslateRemotePathToLocal(fileInfo.FullName, remotePath, localPath);+                    string localFilePath = 
 +                       RemotePath.TranslateRemotePathToLocal( 
 +····························fileInfo.FullName, remotePath, localPath);
                    if (fileInfo.IsDirectory)                     if (fileInfo.IsDirectory)
Line 59: Line 112:
                    else                     else
                    {                     {
-                        Console.WriteLine(string.Format("Downloading file {0}...", fileInfo.FullName));+                        Console.WriteLine("Downloading file {0}...", fileInfo.FullName);
                        // Download file                         // Download file
 +                        string remoteFilePath = RemotePath.EscapeFileMask(fileInfo.FullName);
                        TransferOperationResult transferResult =                         TransferOperationResult transferResult =
-                            session.GetFiles(session.EscapeFileMask(fileInfo.FullName), localFilePath);+                            session.GetFiles(remoteFilePath, localFilePath);
                        // Did the download succeeded?                         // Did the download succeeded?
Line 68: Line 122:
                        {                         {
                            // Print error (but continue with other files)                             // Print error (but continue with other files)
-                            Console.WriteLine(string.Format("Error downloading file {0}: {1}", fileInfo.FullName, transferResult.Failures[0].Message));+                            Console.WriteLine( 
 +································"Error downloading file {0}: {1}", 
 + ·······························fileInfo.FullName, transferResult.Failures[0].Message);
                        }                         }
                    }                     }
Line 85: Line 141:
</code> </code>
-==== PowerShell Example ====+==== [[powershell]] PowerShell Example ====
<code powershell> <code powershell>
param ( param (
-    # Use Generate URL function to obtain a value for -sessionUrl parameter. +    # Use Generate Session URL function to obtain a value for -sessionUrl parameter. 
-    [Parameter(Mandatory)] +    [Parameter(Mandatory = $True)] 
-    $sessionUrl = "sftp://user:mypassword;fingerprint=ssh-rsa-xx-xx-xx@example.com/", +    $sessionUrl = "sftp://user:mypassword;fingerprint=ssh-rsa-xxxxxxxxxxx...@example.com/", 
-    [Parameter(Mandatory)]+    [Parameter(Mandatory = $True)]
    $remotePath,     $remotePath,
-    [Parameter(Mandatory)]+    [Parameter(Mandatory = $True)]
    $localPath     $localPath
) )
Line 105: Line 161:
    # Setup session options from URL     # Setup session options from URL
    $sessionOptions = New-Object WinSCP.SessionOptions     $sessionOptions = New-Object WinSCP.SessionOptions
-    $sessionOptions.ParseUrl($sessionUrl);+    $sessionOptions.ParseUrl($sessionUrl)
    $session = New-Object WinSCP.Session     $session = New-Object WinSCP.Session
Line 119: Line 175:
            $session.EnumerateRemoteFiles(             $session.EnumerateRemoteFiles(
                $remotePath, $Null,                 $remotePath, $Null,
-                ([WinSCP.EnumerationOptions]::EnumerateDirectories -bor [WinSCP.EnumerationOptions]::AllDirectories))+                ([WinSCP.EnumerationOptions]::EnumerateDirectories -bor 
 + ···················[WinSCP.EnumerationOptions]::AllDirectories))
        foreach ($fileInfo in $fileInfos)         foreach ($fileInfo in $fileInfos)
        {         {
-            $localFilePath = $session.TranslateRemotePathToLocal($fileInfo.FullName, $remotePath, $localPath)+            $localFilePath = 
 + ···············[WinSCP.RemotePath]::TranslateRemotePathToLocal( 
 +····················$fileInfo.FullName, $remotePath, $localPath)
            if ($fileInfo.IsDirectory)             if ($fileInfo.IsDirectory)
Line 135: Line 194:
            else             else
            {             {
-                Write-Host ("Downloading file {0}..." -f $fileInfo.FullName)+                Write-Host "Downloading file $($fileInfo.FullName)..."
                # Download file                 # Download file
-                $transferResult = +                $remoteFilePath = [WinSCP.RemotePath]::EscapeFileMask($fileInfo.FullName) 
- ···················$session.GetFiles($session.EscapeFileMask($fileInfo.FullName), $localFilePath);+                $transferResult = $session.GetFiles($remoteFilePath, $localFilePath)
                # Did the download succeeded?                 # Did the download succeeded?
Line 144: Line 203:
                {                 {
                    # Print error (but continue with other files)                     # Print error (but continue with other files)
-                    Write-Host ("Error downloading file {0}: {1}" -f $remoteFilePath, $transferResult.Failures[0].Message)+                    Write-Host ( 
 +························"Error downloading file $($fileInfo.FullName): " + 
 +                       "$($transferResult.Failures[0].Message)")
                }                 }
            }             }
Line 157: Line 218:
    exit 0     exit 0
} }
-catch [Exception] +catch
-+
-    Write-Host $_.Exception.Message +
-    exit 1 +
-+
-</code> +
- +
-===== In the Stable Version ===== +
- +
-==== C# Example ==== +
- +
-<code csharp> +
-using System; +
-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: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); +
- +
-                // Start recursion +
-                downloadDirectory(session, localPath, remotePath); +
-            } +
- +
-            return 0; +
-        } +
-        catch (Exception e) +
-        { +
-            Console.WriteLine("Error: {0}", e); +
-            return 1; +
-        } +
-    } +
- +
-    private static void downloadDirectory(Session session, string localPath, string remotePath) +
-    { +
-        Console.WriteLine(string.Format("Downloading directory {0} ...", remotePath)); +
- +
-        try +
-        { +
-            RemoteDirectoryInfo directoryInfo = session.ListDirectory(remotePath); +
- +
-            foreach (RemoteFileInfo fileInfo in directoryInfo.Files) +
-            { +
-                string remoteFilePath = remotePath + "/" + fileInfo.Name; +
- +
-                if (fileInfo.IsDirectory) +
-                { +
-                    // Skip references to current and parent directories +
-                    if ((fileInfo.Name != ".") && +
-                        (fileInfo.Name != "..")) +
-                    { +
-                        // Recurse into subdirectories +
-                        string localDirPath = localPath + "\\" + fileInfo.Name; +
- +
-                        // Create local subdirectory, if it does not exist yet +
-                        if (!Directory.Exists(localDirPath)) +
-                        { +
-                            Directory.CreateDirectory(localDirPath); +
-                        } +
- +
-                        downloadDirectory(session, localDirPath, remoteFilePath); +
-                    } +
-                } +
-                else +
-                { +
-                    Console.WriteLine(string.Format("Downloading file {0}...", remoteFilePath)); +
-                    // Download file +
-                    TransferOperationResult transferResult = +
-                        session.GetFiles(session.EscapeFileMask(remoteFilePath), (localPath + "\\")); +
- +
-                    // Did the download succeeded? +
-                    if (!transferResult.IsSuccess) +
-                    { +
-                        // Print error (but continue with other files) +
-                        Console.WriteLine(string.Format("Error downloading file {0}: {1}", remoteFilePath, transferResult.Failures[0].Message)); +
-                    } +
-                } +
-            } +
-        } +
-        catch (Exception e) +
-        { +
-            Console.WriteLine(string.Format("Error downloading directory {0}: {1}", remotePath, e.Message)); +
-        } +
-    } +
-+
-</code> +
- +
-==== PowerShell Example ==== +
- +
-<code powershell> +
-param ( +
-    # Use Generate URL function to obtain a value for -sessionUrl parameter. +
-    [Parameter(Mandatory)] +
-    $sessionUrl = "sftp://user:mypassword;fingerprint=ssh-rsa-xx-xx-xx@example.com/", +
-    [Parameter(Mandatory)] +
-    $remotePath, +
-    [Parameter(Mandatory)] +
-    $localPath +
-+
- +
-function DownloadDirectory ($session, $localPath, $remotePath) +
-+
-    Write-Host ("Downloading directory {0} ..." -f $remotePath) +
- +
-    try +
-    { +
-        $directoryInfo = $session.ListDirectory($remotePath) +
- +
-        foreach ($fileInfo in $directoryInfo.Files) +
-        { +
-            $remoteFilePath = ($remotePath + "/" + $fileInfo.Name) +
- +
-            if ($fileInfo.IsDirectory) +
-            { +
-                # Skip references to current and parent directories +
-                if (($fileInfo.Name -ne ".") -and +
-                    ($fileInfo.Name -ne "..")) +
-                { +
-                    # Recurse into subdirectories +
-                    $localDirPath = ($localPath + "\" + $fileInfo.Name) +
- +
-                    # Create local subdirectory, if it does not exist yet +
-                    if (!(Test-Path $localDirPath)) +
-                    { +
-                        New-Item $localDirPath -ItemType directory | Out-Null +
-                    } +
- +
-                    DownloadDirectory $session $localDirPath $remoteFilePath +
-                } +
-            } +
-            else +
-            { +
-                Write-Host ("Downloading file {0}..." -f $remoteFilePath) +
-                # Download file +
-                $transferResult = +
-                    $session.GetFiles($session.EscapeFileMask($remoteFilePath), ($localPath + "\")) +
- +
-                # Did the download succeeded? +
-                if (!$transferResult.IsSuccess) +
-                { +
-                    # Print error (but continue with other files) +
-                    Write-Host ("Error downloading file {0}: {1}" -f $remoteFilePath, $transferResult.Failures[0].Message) +
-                } +
-            } +
-        } +
-    } +
-    catch [Exception] +
-    { +
-        Write-Host ("Error downloading directory {0}: {1}" -f $remotePath, $_.Exception.Message) +
-    } +
-+
- +
-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) +
- +
-        # Start recursion +
-        DownloadDirectory $session $localPath $remotePath +
-    } +
-    finally +
-    { +
-        # Disconnect, clean up +
-        $session.Dispose() +
-    } +
- +
-    exit 0 +
-+
-catch [Exception]+
{ {
-    Write-Host $_.Exception.Message+    Write-Host "Error: $($_.Exception.Message)"
    exit 1     exit 1
} }
</code> </code>
-===== Upload =====+==== Upload ====
-For an example of walking a local tree to upload files individually, see [[library_example_moves_files_keeping_directory_structure|Recursively move files in directory tree to/from SFTP/FTP server while preserving source directory structure]].+For an example of walking a local tree to upload files individually, see [[library_example_moves_files_keeping_directory_structure|*]].
-The upload example calls ''[[library_operationresultbase#check|OperationResultBase.Check]]'', so it aborts on any error. Just replace the call with ''[[library_operationresultbase#issuccess|OperationResultBase.IsSuccess]]'' test as this example does. See [[library_session#results|Capturing Results of Operations]]+The upload example calls ''[[library_operationresultbase#check|OperationResultBase.Check]]'', so it aborts on any error. Just replace the call with ''[[library_operationresultbase#issuccess|OperationResultBase.IsSuccess]]'' test, as the download example above does. See [[library_session#results|Capturing results of operations]].

Last modified: by martin