个性化阅读
专注于IT技术分析

如何在WinForms中使用带有C#的SSH.NET(同步和异步)访问SFTP服务器

本文概述

SFTP代表SSH文件传输协议或安全文件传输协议, 是与SSH打包在一起的独立协议, 在完全安全的连接上以类似的方式工作。尽管SFTP已集成到用户可以使用的许多图形工具中, 但是如果你是开发人员, 则可以将此类功能集成到你的应用程序中。这样, 你可以处理用户使用此工具时的实际操作, 并且他们将继续使用单个应用程序来处理所有事情, 即你的应用程序。

在本文中, 我们将向你展示在WinForms C#中使用广为人知的SSH.NET库使用SFTP时, 如何安装以及如何完成一些基本任务。

1.安装SSH.NET

第一步, 通过NuGET继续在项目中安装SSH.NET库。 SSH.NET是针对.NET的安全Shell(SSH)库, 已针对并行性进行了优化。这个项目的灵感来自从Java移植的Sharp.SSH库, 而且似乎已经有一段时间没有被支持了。该库是使用.NET 4.0进行的完全重写, 没有任何第三方依赖性, 并使用并行性来实现最佳性能。它为同步和异步操作提供SFTP功能, 这正是我们所需要的。

在Visual Studio中打开你的项目, 然后转到窗口右上角的解决方案资源管理器, 然后右键单击项目的解决方案。从上下文菜单中选择”管理NuGet软件包”选项:

使用nuGet安装SSH.NET

从紧急窗口(或选项卡)导航至”浏览”选项卡并搜索SSH.NET。从结果列表中, 选择authro Renci的第一个选项, 然后继续安装:

renci从nuGet储存库安装SSH.NET

库安装完成后, 你将可以在项目中使用它而不会出现问题。不要忘了在你的类的顶部(你要使用它的地方)和其他添加SshNet类型:

using Renci.SshNet;
using Renci.SshNet.Sftp;
using System.IO;

2.用法

用法将基本上通过许多示例来显示, 这些示例说明了如何使用SFTP实现所需的最关键的任务:

列出目录中的文件

你可以使用以下使用SFTPClient.ListDirectory方法的代码段(同步)列出目录的内容:

/// <summary>
/// List a remote directory in the console.
/// </summary>
private void listFiles()
{
    string host = @"yourSftpServer.com";
    string username = "root";
    string password = @"p4ssw0rd";

    string remoteDirectory = "/some/example/directory";

    using (SftpClient sftp = new SftpClient(host, username, password))
    {
        try
        {
            sftp.Connect();

            var files = sftp.ListDirectory(remoteDirectory);

            foreach (var file in files)
            {
                Console.WriteLine(file.Name);
            }

            sftp.Disconnect();
        }
        catch (Exception e)
        {
            Console.WriteLine("An exception has been caught " + e.ToString());
        }
    }
}

或通过在另一个线程中运行代码来异步:

Thread myThread = new System.Threading.Thread(delegate () {
    string remoteDirectory = "/some/example/directory";

    string host = @"yourSftpServer.com";
    string username = "root";
    string password = @"p4ssw0rd";

    using (SftpClient sftp = new SftpClient(host, username, password))
    {
        try
        {
            sftp.Connect();

            var files = sftp.ListDirectory(remoteDirectory);

            foreach (var file in files)
            {
                Console.WriteLine(file.Name);
            }

            sftp.Disconnect();
        }
        catch (Exception er)
        {
            Console.WriteLine("An exception has been caught " + er.ToString());
        }
    }
});

myThread.Start();

连接密钥文件和密码

如果你同时使用私钥文件和密码来连接到SFTP服务器, 则可以使用以下代码段创建连接:

string host = @"yourSftpServer.com";
string username = "root";
string password = @"p4ssw0rd";

PrivateKeyFile keyFile = new PrivateKeyFile(@"path/to/OpenSsh-RSA-key.ppk");
var keyFiles = new[] { keyFile };

var methods = new List<AuthenticationMethod>();
methods.Add(new PasswordAuthenticationMethod(username, password));
methods.Add(new PrivateKeyAuthenticationMethod(username, keyFiles));

ConnectionInfo con = new ConnectionInfo(host, 22, username, methods.ToArray());
using (var client = new SftpClient(con))
{
    client.Connect();

    // Do what you need with the client !

    client.Disconnect();
}

下载单个文件

要下载文件, 可以使用SFTPClient.DownloadFile方法, 并使用System.IO.File.OpenWrite方法在本地写入:

/// <summary>
/// Downloads a file in the desktop synchronously
/// </summary>
public void downloadFile()
{
    string host = @"yourSftpServer.com";
    string username = "root";
    string password = @"p4ssw0rd";

    // Path to file on SFTP server
    string pathRemoteFile = "/var/www/vhosts/some-folder/file_server.txt";
    // Path where the file should be saved once downloaded (locally)
    string pathLocalFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "download_sftp_file.txt");

    using (SftpClient sftp = new SftpClient(host, username, password))
    {
        try
        {
            sftp.Connect();

            Console.WriteLine("Downloading {0}", pathRemoteFile);

            using (Stream fileStream = File.OpenWrite(pathLocalFile))
            {
                sftp.DownloadFile(pathRemoteFile, fileStream);
            }

            sftp.Disconnect();
        }
        catch (Exception er)
        {
            Console.WriteLine("An exception has been caught " + er.ToString());
        }
    }
}

或者, 你可以使其异步创建另一个线程并在其中执行代码:

Thread myThread = new System.Threading.Thread(delegate () {
    string host = @"yourSftpServer.com";
    string username = "root";
    string password = @"p4ssw0rd";

    // Path to file on SFTP server
    string pathRemoteFile = "/var/www/vhosts/some-folder/file_server.txt";
    // Path where the file should be saved once downloaded (locally)
    string pathLocalFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "download_sftp_file.txt");

    using (SftpClient sftp = new SftpClient(host, username, password))
    {
        try
        {
            sftp.Connect();

            Console.WriteLine("Downloading {0}", pathRemoteFile);

            using (Stream fileStream = File.OpenWrite(pathLocalFile))
            {
                sftp.DownloadFile(pathRemoteFile, fileStream);
            }

            sftp.Disconnect();
        }
        catch (Exception er)
        {
            Console.WriteLine("An exception has been caught " + er.ToString());
        }
    }
});

myThread.Start();

下载整个目录

如果你需要下载整个目录(甚至是子文件夹和子文件), 则需要创建2个函数, 其中之一是递归的。第一个功能是DownloadFile, 它允许你通过远程目录和本地路径作为参数下载文件。第二个功能是DownloadDirectory方法, 该方法将列出Providen目录中的所有文件并对其进行迭代。分别地, 如果该项是文件, 那么它将使用DownloadFile方法下载它, 或者如果它是一个文件夹, 则它将创建它:

/// <summary>
/// Downloads a remote directory into a local directory
/// </summary>
/// <param name="client"></param>
/// <param name="source"></param>
/// <param name="destination"></param>
private void DownloadDirectory(SftpClient client, string source, string destination, bool recursive = false)
{
    // List the files and folders of the directory
    var files = client.ListDirectory(source);

    // Iterate over them
    foreach (SftpFile file in files)
    {
        // If is a file, download it
        if (!file.IsDirectory && !file.IsSymbolicLink)
        {
            DownloadFile(client, file, destination);
        }
        // If it's a symbolic link, ignore it
        else if (file.IsSymbolicLink)
        {
            Console.WriteLine("Symbolic link ignored: {0}", file.FullName);
        }
        // If its a directory, create it locally (and ignore the .. and .=) 
        //. is the current folder
        //.. is the folder above the current folder -the folder that contains the current folder.
        else if (file.Name != "." && file.Name != "..")
        {
            var dir = Directory.CreateDirectory(Path.Combine(destination, file.Name));
            // and start downloading it's content recursively :) in case it's required
            if (recursive)
            {
                DownloadDirectory(client, file.FullName, dir.FullName);
            }
        }
    }
}

/// <summary>
/// Downloads a remote file through the client into a local directory
/// </summary>
/// <param name="client"></param>
/// <param name="file"></param>
/// <param name="directory"></param>
private void DownloadFile(SftpClient client, SftpFile file, string directory)
{
    Console.WriteLine("Downloading {0}", file.FullName);

    using (Stream fileStream = File.OpenWrite(Path.Combine(directory, file.Name)))
    {
        client.DownloadFile(file.FullName, fileStream);
    }
}

接下来, 你可以继续使用凭​​据创建客户端, 并使用先前创建的方法开始下载远程目录。请注意, 由于下载整个目录会花费一些时间, 因此建议仅以异步方式(创建线程)使用它, 但这只是一个建议, 你可以解开代码:

Thread myThread = new System.Threading.Thread(delegate () {
    string host = @"yourSftpServer.com";
    string username = "root";
    string password = @"p4ssw0rd";

    // Path to folder on SFTP server
    string pathRemoteDirectory = "/var/www/vhosts/some-folder-to-download";
    // Path where the file should be saved once downloaded (locally)
    string pathLocalDirectory = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "example-local-folder");

    using (SftpClient sftp = new SftpClient(host, username, password))
    {
        try
        {
            sftp.Connect();

            // By default, the method doesn't download subdirectories
            // therefore you need to indicate that you want their content too
            bool recursiveDownload = true;

            // Start download of the directory
            DownloadDirectory(
                sftp, pathRemoteDirectory, pathLocalDirectory, recursiveDownload
            );
            
            sftp.Disconnect();
        }
        catch (Exception er)
        {
            Console.WriteLine("An exception has been caught " + er.ToString());
        }
    }
});

myThread.Start();

删除远端档案

要从远程目录中删除文件, 请使用SFTPClient.DeleteFile方法:

/// <summary>
/// Delete a remote file
/// </summary>
private void deleteFile()
{
    string host = @"yourSftpServer.com";
    string username = "root";
    string password = @"p4ssw0rd";

    // Path to folder on SFTP server
    string pathRemoteFileToDelete = "/var/www/vhosts/folder/somefile.txt";

    using (SftpClient sftp = new SftpClient(host, username, password))
    {
        try
        {
            sftp.Connect();

            // Delete file
            sftp.DeleteFile(pathRemoteFileToDelete);

            sftp.Disconnect();
        }
        catch (Exception er)
        {
            Console.WriteLine("An exception has been caught " + er.ToString());
        }
    }
}

编码愉快!

赞(0)
未经允许不得转载:srcmini » 如何在WinForms中使用带有C#的SSH.NET(同步和异步)访问SFTP服务器

评论 抢沙发

评论前必须登录!