2012-11-26 13 views
6

Ich verwende die Renci.SshNet-Bibliothek, um mithilfe von SFTP rekursiv eine Liste von Dateien und Verzeichnissen zu erhalten. Ich kann SFTP Site verbinden, aber ich bin nicht sicher, wie man eine Liste von Verzeichnissen und Akten rekursiv in C# holt. Ich habe keine nützlichen Beispiele gefunden.SshNet SFTP Dateien und Verzeichnisse abrufen

Hat jemand das versucht? Wenn ja, können Sie einen Beispielcode zum rekursiven Abrufen dieser Dateien und Ordner bereitstellen.

Danke, Prav

Antwort

2

Versuchen Sie folgendes:

var filePaths = client.ListDirectory(client.WorkingDirectory); 
9

Diese Bibliothek hat einige Macken, die diese rekursive Auflistung heikel, weil die Wechselwirkung zwischen dem ChangeDirectory und ListDirectory machen nicht wie erwartet funktionieren kann.

Die folgende tut nicht Liste der Dateien im Verzeichnis/home stattdessen listet die Dateien im Verzeichnis/(root) Verzeichnis:

sftp.ChangeDirectory("home"); 
sftp.ListDirectory("").Select (s => s.FullName); 

Das folgende ist nicht Arbeit und gibt einen SftpPathNotFoundException:

sftp.ChangeDirectory("home"); 
sftp.ListDirectory("home").Select (s => s.FullName); 

im folgenden ist der richtige Weg, um die Dateien im Verzeichnis/home zur Liste

sftp.ChangeDirectory("/"); 
sftp.ListDirectory("home").Select (s => s.FullName); 

Das ist ziemlich verrückt, wenn Sie mich fragen. Das Festlegen des Standardverzeichnisses mit der Methode ChangeDirectory hat keine Auswirkungen auf die Methode ListDirectory, es sei denn, Sie geben einen Ordner im Parameter dieser Methode an. Scheint wie ein Bug sollte dafür geschrieben werden.

Wenn Sie also Ihre rekursive Funktion schreiben, müssen Sie das Standardverzeichnis einmal festlegen und dann das Verzeichnis im ListDirectory-Aufruf ändern, während Sie über die Ordner iterieren. Die Auflistung gibt eine Auflistung von SftpFiles zurück. Diese können dann einzeln auf IsDirectory == true überprüft werden. Beachten Sie, dass die Auflistung auch die . und .. Einträge (die Verzeichnisse sind) zurückgibt. Sie sollten diese überspringen, wenn Sie eine Endlosschleife vermeiden möchten.

:-)

EDIT 2/23/2018

ich einige meiner alten Antworten überprüfen und möchte mich für die Antwort oben und geben Sie die folgenden Arbeits Code entschuldigen. Beachten Sie, dass dieses Beispiel nicht ChangeDirectory erfordert, da sie die Fullname für die ListDirectory ist mit:

void Main() 
{ 
    using (var client = new Renci.SshNet.SftpClient("sftp.host.com", "user", "password")) 
    { 
     var files = new List<String>(); 
     client.Connect(); 
     ListDirectory(client, ".", ref files); 
     client.Disconnect(); 
     files.Dump(); 
    } 
} 

void ListDirectory(SftpClient client, String dirName, ref List<String> files) 
{ 
    foreach (var entry in client.ListDirectory(dirName)) 
    { 

     if (entry.IsDirectory) 
     { 
      ListDirectory(client, entry.FullName, ref files); 
     } 
     else 
     { 
      files.Add(entry.FullName); 
     } 
    } 
} 
+4

sftp.ListDirectory ("") funktioniert nicht, aber sftp.ListDirectory (".") Tut - erinnern, '.' bedeutet "aktuelles Verzeichnis". Es scheint jedoch nicht die '~' Verknüpfung für Home-Ordner zu unterstützen. – Gargravarr

+0

Danke für die Erklärung, gibt es ein komplettes Beispiel, wie man eine Liste oder eine Baumstruktur aller Verzeichnisse und Unterverzeichnisse ab einem bestimmten Stammordner erhält? Ich frage mich, warum ssh.net keine bool recursive in der ListDirectory-Methode selbst bietet. Gibt es heutzutage eine bessere Lösung für .net? I.e. eine bessere lib, die auch frei ist, die diese grundlegenden aufgaben bereits implementiert? Ein funktionierendes Beispiel wäre jedoch sehr hilfreich, danke! – Erik

0

ich erreicht habe dies mit Rekursion. Erstellt eine Klasse TransportResponse wie diese

public class TransportResponse 
{ 
    public string directoryName { get; set; } 
    public string fileName { get; set; } 
    public DateTime fileTimeStamp { get; set; } 
    public MemoryStream fileStream { get; set; } 
    public List<TransportResponse> lstTransportResponse { get; set; } 
} 

ich eine Liste der TransportResponse Klasse erstellen. Wenn der Verzeichnisname nicht null ist, wird es eine Liste der gleichen Klasse enthält, die die Dateien in diesem Verzeichnis als Memory haben werden (dies kann nach Ihrem Anwendungsfall geändert werden)

List<TransportResponse> lstResponse = new List<TransportResponse>(); 
using (var client = new SftpClient(connectionInfo)) 
    { 
      try 
      { 
        Console.WriteLine("Connecting to " + connectionInfo.Host + " ..."); 
        client.Connect(); 
        Console.WriteLine("Connected to " + connectionInfo.Host + " ..."); 
      } 
      catch (Exception ex) 
      { 
        Console.WriteLine("Could not connect to "+ connectionInfo.Host +" server. Exception Details: " + ex.Message); 
      } 
      if (client.IsConnected) 
      { 
        var files = client.ListDirectory(transport.SourceFolder); 
        lstResponse = downloadFilesInDirectory(files, client); 
        client.Disconnect(); 
      } 
      else 
      { 
        Console.WriteLine("Could not download files from "+ transport.TransportIdentifier +" because client was not connected."); 
      } 
    } 



private static List<TransportResponse> downloadFilesInDirectory(IEnumerable<SftpFile> files, SftpClient client) 
    { 
     List<TransportResponse> lstResponse = new List<TransportResponse>(); 
     foreach (var file in files) 
     { 
      if (!file.IsDirectory) 
      { 
       if (file.Name != "." && file.Name != "..") 
       { 
        if (!TransportDAL.checkFileExists(file.Name, file.LastWriteTime)) 
        { 
         using (MemoryStream fs = new MemoryStream()) 
         { 
          try 
          { 
           Console.WriteLine("Reading " + file.Name + "..."); 
           client.DownloadFile(file.FullName, fs); 
           fs.Seek(0, SeekOrigin.Begin); 
           lstResponse.Add(new TransportResponse { fileName = file.Name, fileTimeStamp = file.LastWriteTime, fileStream = new MemoryStream(fs.GetBuffer()) }); 
          } 
          catch(Exception ex) 
          { 
           Console.WriteLine("Error reading File. Exception Details: " + ex.Message); 
          } 
         } 
        } 
        else 
        { 
         Console.WriteLine("File was downloaded previously"); 
        } 
       } 
      } 
      else 
      { 
       if (file.Name != "." && file.Name != "..") 
       { 
        lstResponse.Add(new TransportResponse { directoryName = file.Name,lstTransportResponse = downloadFilesInDirectory(client.ListDirectory(file.Name), client) }); 
       }     
      } 
     } 

     return lstResponse; 
    } 

Hoffnung, das hilft.Dank

0

@Carlos Bos

Diese Bibliothek hat einige Macken, die diese rekursive Auflistung heikel machen, weil die Wechselwirkung zwischen dem Change und Listdirectory nicht wie erwartet funktionieren kann.

richtig

Es funktioniert gut, wenn die Change() Parameter sind ""

aber wenn Sie das tun

SftpClient sftp ...; 
sftp.ChangeDirectory("some_folder"); 
//get file list 
List<SftpFile> fileList = sftp.ListDirectory("some_folder").ToList(); 

dann gibt es eine Behauptung, weil die Listdirectory() -Aufruf erwartet „some_folder/some_folder“

Die Abhilfe I verwenden zu speichern und das aktuelle Verzeichnis wiederherstellen, bevor ein Remote-Upload/umbenennen „some_folder“, und Sie müssen diese Ordner vor der Operation zur Liste (zB um zu sehen, existiert die Datei bereits)

string working_directory = sftp.WorkingDirectory; 
sftp.ChangeDirectory("some_folder"); 
sftp.RenameFile("name", "new_name"); 
sftp.ChangeDirectory(working_directory); 

zu überprüfen, ob die Datei vorhanden ist, ist dieser Aufruf ausreichend

sftp.Exists(path) 

oder wenn Sie einige andere Kriterien, wie Groß- und Kleinschreibung oder nicht

public FileExistence checkFileExists(string folder, string fileName) 
    { 
     //get file list 
     List<SftpFile> fileList = sftp.ListDirectory(folder).ToList(); 

     if (fileList == null) 
     { 
     return FileExistence.UNCONFIRMED; 
     } 

     foreach (SftpFile f in fileList) 
     { 
     Console.WriteLine(f.ToString()); 
     //a not case sensitive comparison is made 
     if (f.IsRegularFile && f.Name.ToLower() == fileName.ToLower()) 
     { 
      return FileExistence.EXISTS; 
     } 
     } 

     //if not found in traversal , it does not exist 
     return FileExistence.DOES_NOT_EXIST; 
    } 

wo FileExistence ist hinzufügen möchten

public enum FileExistence 
    { 
     EXISTS, 
     DOES_NOT_EXIST, 
     UNCONFIRMED 
    }; 
Verwandte Themen