【问题标题】:Download files from SFTP with SSH.NET library使用 SSH.NET 库从 SFTP 下载文件
【发布时间】:2014-07-05 08:45:12
【问题描述】:
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);
        }
    }
}

我正在使用 SSH.NET (Renci.SshNet) 库来处理 SFTP 服务器。我需要做的是根据今天的日期从 SFTP 服务器上的特定文件夹中获取文件。然后将这些文件从 SFTP 服务器复制到我的服务器的本地驱动器。

上面是我的代码,但它不起作用。有时它说文件不存在,但有时我要下载的文件不会在我的本地服务器上,但我需要下载当天上传到远程文件夹的所有文件。

有人可以看看有什么问题吗?我相信它与流部分有关。除了上传文件外,我还使用过很多 FTP,这些文件我使用了一些以前的代码,并认为我可以扭转这个过程,但这不起作用。我使用的代码基于此example

【问题讨论】:

    标签: c# .net ssh sftp


    【解决方案1】:

    这解决了我的问题。

    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);
        }
    }
    

    【讨论】:

      【解决方案2】:

      Massimiliano 的解决方案有一个问题会导致文件无法完全下载。 FileStream 必须关闭。这对于加密文件来说尤其是一个问题。他们不会在不关闭流的情况下间歇性地完全解密。

      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);
          }
      }
      

      【讨论】:

        【解决方案3】:

        使用 SSH.NET 库下载文件的简单工作代码是:

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

        另见Downloading a directory using SSH.NET SFTP in C#


        解释一下为什么你的代码不起作用:

        SftpClient.DownloadFile 的第二个参数是用于写入下载内容的流。

        您传递的是读取流而不是写入流。此外,您打开读取流的路径是远程路径,不能与仅在本地文件上运行的 File 类一起使用。

        只需丢弃 File.OpenRead 行并使用之前的 File.OpenWrite 调用的结果(您现在根本没有使用):

        Stream file1 = File.OpenWrite(localFileName);
        
        sftp.DownloadFile(file.FullName, file1);
        

        或者更好的是,使用File.Create 丢弃本地文件可能包含的任何以前的内容。

        我不确定您的 localFileName 是否应该包含完整路径,或者只是文件名。因此,如有必要,您可能还需要添加路径(将localFileNamesDir 结合起来?)

        【讨论】:

          【解决方案4】:

          我的@Merak Marey 代码版本。我正在检查文件是否已经存在以及 .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();
          
                  }
          

          【讨论】:

          • 如果你想添加一些基于扩展使用 FileInfo fi 的东西,你可以简单地做:string ext = fi.Extension; 和一个开关。因为LOVE-LETTER-FOR-YOU.TXT.vbs 将是误报。或Path.GetExtension(myFilePath);
          • 当心,您正在检查文件名是否包含“.TXT”,并且根据服务器操作系统,您可能会得到“.txt”(小写)。将 remoteFilename 变量小写并使用是个好主意它也适用于条件而不是 file.Name...
          • 更好:if (!file.Name.ToLower().EndsWith(".txt"))
          【解决方案5】:

          虽然该示例有效,但它不是处理流的正确方法...

          您需要确保使用 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.OpenWrite(localDirectory + remoteFileName))
                              { 
                                  sftp.DownloadFile(remoteDirectory + remoteFileName, file1);
                              }
                      }
          
                  }
              }
          

          【讨论】:

            【解决方案6】:

            如果不提供任何具体的错误信息,就很难给出具体的建议。

            但是,我使用相同的示例并且在 File.OpenWrite 上获得了权限异常 - 使用 localFileName 变量,因为使用 Path.GetFile 指向的位置显然没有打开文件的权限 > C: \ProgramFiles\IIS(Express)\filename.doc

            我发现使用 System.IO.Path.GetFileName 不正确,改用 System.IO.Path.GetFullPath,指向以“C:\...”开头的文件

            还可以在 FileExplorer 中打开您的解决方案,并为 asp.net 授予文件或包含该文件的任何文件夹的权限。那时我能够下载我的文件。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2014-12-01
              • 1970-01-01
              • 1970-01-01
              • 2022-01-01
              • 1970-01-01
              相关资源
              最近更新 更多