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. 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.

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: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(string.Format("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(string.Format("Error downloading file {0}: {1}", fileInfo.FullName, transferResult.Failures[0].Message));
                        }
                    }
                }
            }
 
            return 0;
        }
        catch (Exception e)
        {
            Console.WriteLine("Error: {0}", e);
            return 1;
        }
    }
}

PowerShell Example

param (
    # Use Generate 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 {0}..." -f $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 {0}: {1}" -f $remoteFilePath, $transferResult.Failures[0].Message)
                }
            }
        }
    }
    finally
    {
        # Disconnect, clean up
        $session.Dispose()
    }
 
    exit 0
}
catch [Exception]
{
    Write-Host ("Error: {0}" -f $_.Exception.Message)
    exit 1
}

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.

Advertisements:

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

 
  library_example_recursive_download_custom_error_handling.txt · Last modified: by martin
 

Search Documentation

This page

Donate

About donations

$9   $19   $49   $99

About donations

Recommend

Associations

Site design by Black Gate