Search code examples
c#treeviewsftpwinscpwinscp-net

Showing SFTP directory structure with TreeView using WinSCP in C#


I'm trying to achieve the following, building a TreeView component showing all the directories and subdirectories of an SFTP folder using the WinSCP .NET assembly API.

like this:

Home ---->SubFolder
     |
     |---->Another Folder -------> MyFolder1
     |                  | -------> MyFolder2
     |
     |---->MyOtherFolder 

I'm following this approach, but somehow for the WinSCP RemoteDirectoryInfo it doesn't work.

private void ListDirectory(TreeView treeView, string path)
{
    treeView.Nodes.Clear();
    var rootDirectoryInfo = new DirectoryInfo(path);
    treeView.Nodes.Add(CreateDirectoryNode(rootDirectoryInfo));
}

private static TreeNode CreateDirectoryNode(DirectoryInfo directoryInfo)
{
    var directoryNode = new TreeNode(directoryInfo.Name);
    foreach (var directory in directoryInfo.GetDirectories())
        directoryNode.Nodes.Add(CreateDirectoryNode(directory));
    foreach (var file in directoryInfo.GetFiles())
        directoryNode.Nodes.Add(new TreeNode(file.Name));
    return directoryNode;
}

When I follow this approach using WinSCP.RemoteDirectoryInfo instead of DirectoryInfo, it's not working because RemoteDirectoryInfo doesn't have the same properties and methods as IO.DirectoryInfo.

I see that the better way to go might be using EnumerateDirectories, which will show all folders and subfolders.

var fileInfos =
    sftpSession.EnumerateRemoteFiles(
        "/source", "*",
        WinSCP.EnumerationOptions.AllDirectories |
            WinSCP.EnumerationOptions.EnumerateDirectories);           
foreach (RemoteFileInfo fi in fileInfos)
{
    if (fi.IsDirectory) { 
        treeView1.Nodes.Add(fi.FullName);
    }
}

but this results in this:

folder tree

Where I'm trying to achieve this:

folder tree


Solution

  • Use WinSCP Session.ListDirectory to obtain list of subdirectories and files and a particular folder (instead of DirectoryInfo.GetDirectories and DirectoryInfo.GetFiles from your code).

    And use RemoteFileInfo.IsDirectory to differentiate subfolders and files.

    private void ListDirectory(TreeView treeView, string path)
    {
        treeView.Nodes.Clear();
        treeView.Nodes.Add(CreateDirectoryNode(path));
    }
    
    private TreeNode CreateDirectoryNode(string path)
    {
        var directoryNode = new TreeNode(RemotePath.GetFileName(path));
        var entries = sftpSession.ListDirectory(path).Files;
        var directories =
            files.Where(_ => _.IsDirectory &&
                        !_.IsParentDirectory && !_.IsThisDirectory);
        foreach (var directory in directories)
            directoryNode.Nodes.Add(CreateDirectoryNode(directory.FullName));
        foreach (var file in entries.Where(_ => !_.IsDirectory))
            directoryNode.Nodes.Add(new TreeNode(file.Name));
        return directoryNode;
    }