简体   繁体   English

使用 SSH.NET 库从 SFTP 下载文件

[英]Download files from SFTP with SSH.NET library

string host = @"ftphost";
string username = "user";
string password = "********";
string localFileName  = System.IO.Path.GetFileName(@"localfilename");
string remoteDirectory = "/export/";
using (var sftp = new SftpClient(host, username, password))
{
    sftp.Connect();
    var files = sftp.ListDirectory(remoteDirectory);
    foreach (var file in files)
    {
        if (!file.Name.StartsWith("."))
        {
            string remoteFileName = file.Name;
            if (file.LastWriteTime.Date == DateTime.Today)

            Console.WriteLine(file.FullName);

            File.OpenWrite(localFileName);

            string sDir = @"localpath";

            Stream file1 = File.OpenRead(remoteDirectory + file.Name);
            sftp.DownloadFile(remoteDirectory, file1);
        }
    }
}

I am using SSH.NET ( Renci.SshNet ) library to work with an SFTP server.我正在使用 SSH.NET ( Renci.SshNet ) 库来处理 SFTP 服务器。 What I need to do is grab files from a specific folder on the SFTP server based on today's date.我需要做的是根据今天的日期从 SFTP 服务器上的特定文件夹中获取文件。 Then copy those files from the SFTP server to a local drive a server of mine.然后将这些文件从 SFTP 服务器复制到我的服务器的本地驱动器。

Above is the code I have but it is not working.以上是我拥有的代码,但它不起作用。 Sometimes it says file does not exist but sometimes the files I will be downloading will not be on my local servers but I need to download whatever files were uploaded to the remote folder for that day.有时它说文件不存在,但有时我要下载的文件不会在我的本地服务器上,但我需要下载当天上传到远程文件夹的所有文件。

Can someone take a look and see what is wrong?有人可以看看,看看有什么问题吗? I believe it has something to do with the stream portion.我相信它与流部分有关。 I have worked with FTP much besides uploading files which I took some previous code I had and thought I could reverse the process but that isn't working.除了上传文件外,我还使用过很多 FTP,这些文件我使用了一些以前的代码,并认为我可以扭转这个过程,但这不起作用。 The code I used is based off of this example .我使用的代码基于此示例

A simple working code to download a file with SSH.NET library is:使用 SSH.NET 库下载文件的简单工作代码是:

using (Stream fileStream = File.Create(@"C:\target\local\path\file.zip"))
{
    sftp.DownloadFile("/source/remote/path/file.zip", fileStream);
}

See also Downloading a directory using SSH.NET SFTP in C# .另请参阅在 C# 中使用 SSH.NET SFTP 下载目录


To explain, why your code does not work:解释一下,为什么您的代码不起作用:

The second parameter of SftpClient.DownloadFile is a stream to write a downloaded contents to. SftpClient.DownloadFile的第二个参数是用于将下载内容写入的流。

You are passing in a read stream instead of a write stream.您传入的是读取流而不是写入流。 And moreover the path you are opening read stream with is a remote path, what cannot work with File class operating on local files only.此外,您打开读取流的路径是远程路径,不能与仅在本地文件上操作的File类一起使用。

Just discard the File.OpenRead line and use a result of previous File.OpenWrite call instead (that you are not using at all now):只需丢弃File.OpenRead行并改用先前File.OpenWrite调用的结果(您现在根本没有使用):

Stream file1 = File.OpenWrite(localFileName);

sftp.DownloadFile(file.FullName, file1);

Or even better, use File.Create to discard any previous contents that the local file may have.或者更好的是,使用File.Create丢弃本地文件可能具有的任何先前内容。

I'm not sure if your localFileName is supposed to hold full path, or just file name.我不确定您的localFileName是否应该包含完整路径,或者只是文件名。 So you may need to add a path too, if necessary (combine localFileName with sDir ?)因此,如有必要,您可能还需要添加路径(将localFileNamesDir结合起来?)

While the example works, its not the correct way to handle the streams...虽然该示例有效,但它不是处理流的正确方法......

You need to ensure the closing of the files/streams with the using clause.. Also, add try/catch to handle IO errors...您需要确保使用 using子句关闭文件/流。此外,添加 try/catch 以处理 IO 错误...

       public void DownloadAll()
    {
        string host = @"sftp.domain.com";
        string username = "myusername";
        string password = "mypassword";
        
        string remoteDirectory = "/RemotePath/";
        string localDirectory = @"C:\LocalDriveFolder\Downloaded\";

        using (var sftp = new SftpClient(host, username, password))
        {
            sftp.Connect();
            var files = sftp.ListDirectory(remoteDirectory);
            
            foreach (var file in files)
            {
                string remoteFileName = file.Name;
                if ((!file.Name.StartsWith(".")) && ((file.LastWriteTime.Date == DateTime.Today))

                    using (Stream file1 = File.Create(localDirectory + remoteFileName))
                    { 
                        sftp.DownloadFile(remoteDirectory + remoteFileName, file1);
                    }
            }

        }
    }

My version of @Merak Marey's Code.我的@Merak Marey 代码版本。 I am checking if files exist already and different download directories for .txt and other files我正在检查文件是否已经存在以及 .txt 和其他文件的不同下载目录

        static void DownloadAll()
    {
        string host = "xxx.xxx.xxx.xxx";
        string username = "@@@";
        string password = "123";string remoteDirectory = "/IN/";
        string finalDir = "";
        string localDirectory = @"C:\filesDN\";
        string localDirectoryZip = @"C:\filesDN\ZIP\";
        using (var sftp = new SftpClient(host, username, password))
        {
            Console.WriteLine("Connecting to " + host + " as " + username);
            sftp.Connect();
            Console.WriteLine("Connected!");
            var files = sftp.ListDirectory(remoteDirectory);

            foreach (var file in files)
            {

                string remoteFileName = file.Name;

                if ((!file.Name.StartsWith(".")) && ((file.LastWriteTime.Date == DateTime.Today)))
                { 

                    if (!file.Name.Contains(".TXT"))
                    {
                        finalDir = localDirectoryZip;
                    } 
                    else 
                    {
                        finalDir = localDirectory;
                    }


                    if (File.Exists(finalDir  + file.Name))
                    {
                        Console.WriteLine("File " + file.Name + " Exists");
                    }else{
                        Console.WriteLine("Downloading file: " + file.Name);
                          using (Stream file1 = File.OpenWrite(finalDir + remoteFileName))
                    {
                        sftp.DownloadFile(remoteDirectory + remoteFileName, file1);
                    }
                    }
                }
            }



            Console.ReadLine();

        }

This solves the problem on my end.这解决了我的问题。

var files = sftp.ListDirectory(remoteVendorDirectory).Where(f => !f.IsDirectory);

foreach (var file in files)
{
    var filename = $"{LocalDirectory}/{file.Name}";
    if (!File.Exists(filename))
    {
        Console.WriteLine("Downloading  " + file.FullName);
        using (var localFile = File.OpenWrite(filename))
              sftp.DownloadFile(file.FullName, localFile);
    }
}

Massimiliano's solution has one problem which will lead to files not being completely downloaded. Massimiliano 的解决方案有一个问题,会导致文件无法完全下载。 The FileStream must be closed. FileStream 必须关闭。 This is especially a problem for encrypted files.这对于加密文件来说尤其是一个问题。 They won't completely decrypt intermittently without closing the stream.他们不会在不关闭流的情况下间歇性地完全解密。

var files = sftp.ListDirectory(remoteVendorDirectory).Where(f => !f.IsDirectory);

foreach (var file in files)
{
    var filename = $"{LocalDirectory}/{file.Name}";
    if (!File.Exists(filename))
    {
        Console.WriteLine("Downloading  " + file.FullName);
        using (var localFile = File.OpenWrite(filename))
            sftp.DownloadFile(file.FullName, localFile);
    }
}

Without you providing any specific error message, it's hard to give specific suggestions.没有你提供任何具体的错误信息,很难给出具体的建议。

However, I was using the same example and was getting a permissions exception on File.OpenWrite - using the localFileName variable, because using Path.GetFile was pointing to a location that obviously would not have permissions for opening a file > C:\ProgramFiles\IIS(Express)\filename.doc但是,我使用的是相同的示例并且在 File.OpenWrite 上获得了权限异常 - 使用 localFileName 变量,因为使用 Path.GetFile 指向的位置显然没有打开文件的权限 > C:\ProgramFiles\ IIS(Express)\文件名.doc

I found that using System.IO.Path.GetFileName is not correct, use System.IO.Path.GetFullPath instead, point to your file starting with "C:\..."我发现使用 System.IO.Path.GetFileName 不正确,请改用 System.IO.Path.GetFullPath,指向以“C:\...”开头的文件

Also open your solution in FileExplorer and grant permissions to asp.net for the file or any folders holding the file.还要在 FileExplorer 中打开您的解决方案,并为 asp.net 授予文件或包含该文件的任何文件夹的权限。 I was able to download my file at that point.那时我能够下载我的文件。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM