2011-02-01 14 views

risposta

10

Prima di tutto bisogna elencare tutti i file nella directory:

public static List<string> DirectoryListing(string Path, string ServerAdress, string Login, string Password) 
    { 
     FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://" + ServerAdress + Path); 
     request.Credentials = new NetworkCredential(Login, Password); 

     request.Method = WebRequestMethods.Ftp.ListDirectory;    

     FtpWebResponse response = (FtpWebResponse)request.GetResponse(); 
     Stream responseStream = response.GetResponseStream(); 
     StreamReader reader = new StreamReader(responseStream); 

     List<string> result = new List<string>(); 

     while (!reader.EndOfStream) 
     { 
      result.Add(reader.ReadLine()); 
     } 

     reader.Close(); 
     response.Close(); 

     return result; 
    } 

allora avete bisogno di un metodo per eliminare un singolo file (perché è possibile eliminare una cartella solo se è vuota):

public static void DeleteFTPFile(string Path, string ServerAdress, string Login, string Password) 
    { 
     FtpWebRequest clsRequest = (System.Net.FtpWebRequest)WebRequest.Create("ftp://" + ServerAdress + Path); 
     clsRequest.Credentials = new System.Net.NetworkCredential(Login, Password); 

     clsRequest.Method = WebRequestMethods.Ftp.DeleteFile; 

     string result = string.Empty; 
     FtpWebResponse response = (FtpWebResponse)clsRequest.GetResponse(); 
     long size = response.ContentLength; 
     Stream datastream = response.GetResponseStream(); 
     StreamReader sr = new StreamReader(datastream); 
     result = sr.ReadToEnd(); 
     sr.Close(); 
     datastream.Close(); 
     response.Close(); 
    } 

E infine:

public static void DeleteFTPDirectory(string Path, string ServerAdress, string Login, string Password) 
{ 
     FtpWebRequest clsRequest = (System.Net.FtpWebRequest)WebRequest.Create("ftp://" + ServerAdress + Path); 
     clsRequest.Credentials = new System.Net.NetworkCredential(Login, Password); 

     List<string> filesList = DirectoryListing(Path, ServerAdress, Login, Password); 

     foreach (string file in filesList) 
     { 
      DeleteFTPFile(Path + file, ServerAdress, Login, Password); 
     } 

     clsRequest.Method = WebRequestMethods.Ftp.RemoveDirectory; 

     string result = string.Empty; 
     FtpWebResponse response = (FtpWebResponse)clsRequest.GetResponse(); 
     long size = response.ContentLength; 
     Stream datastream = response.GetResponseStream(); 
     StreamReader sr = new StreamReader(datastream); 
     result = sr.ReadToEnd(); 
     sr.Close(); 
     datastream.Close(); 
     response.Close(); 
    } 

si può facilmente chiamare questo genere (per me questi metodi sono in una classe denominata "Ftp"):

Ftp.DeleteFTPDirectory (the_path_of_your_folder_in_ftp, your_server_address, your_ftp_login, your_ftp_password);

Naturalmente, sarà necessario personalizzare quelle linee, ma ha funzionato perfettamente per me :)

4

Non c'è alcun supporto per operazioni ricorsive nel FtpWebRequest class (o qualsiasi altra applicazione FTP nel framework .NET). È necessario implementare la ricorsione da soli:

  • Lista directory remota
  • Iterate le voci, l'eliminazione di file e recursing in sottodirectory (messa in vendita di nuovo, ecc)

parte difficile è quello di identificare file da sottodirectory. Non c'è modo di farlo in modo portatile con lo FtpWebRequest. Il FtpWebRequest purtroppo non supporta il comando MLSD, che è l'unico modo portatile per recuperare l'elenco di directory con gli attributi di file nel protocollo FTP. Vedi anche Checking if object on FTP server is file or directory.

Le opzioni disponibili sono:

  • fare un'operazione su un nome di file che è certo di fallire per un file e di successo per la directory (o viceversa). Cioè puoi provare a scaricare il "nome". Se questo succede, è un file, se fallisce, è una directory. Ma questo può diventare un problema di prestazioni, quando hai un gran numero di voci.
  • Potresti essere fortunato e nel tuo caso specifico, puoi dire un file da una directory con un nome di file (ad es.tutti i file hanno un'estensione, mentre le sottodirectory no)
  • Si utilizza un elenco di directory lungo (metodo LIST = ListDirectoryDetails) e si tenta di analizzare un elenco specifico del server. Molti server FTP utilizzano l'elenco * nix-style, in cui si identifica una directory tramite lo d all'inizio della voce. Ma molti server usano un formato diverso. L'esempio seguente utilizza questo approccio (assumendo il formato * nix).
  • In questo caso specifico, è sufficiente provare a eliminare la voce come file. Se l'eliminazione non riesce, provare ad elencare la voce come directory. Se l'elenco riesce, si presuppone che si tratta di una cartella e procedere di conseguenza. Sfortunatamente alcuni server non commettono errori quando si tenta di elencare un file. Restituiranno solo un elenco con una singola voce per il file.
static void DeleteFtpDirectory(string url, NetworkCredential credentials) 
{ 
    FtpWebRequest listRequest = (FtpWebRequest)WebRequest.Create(url); 
    listRequest.Method = WebRequestMethods.Ftp.ListDirectoryDetails; 
    listRequest.Credentials = credentials; 

    List<string> lines = new List<string>(); 

    using (FtpWebResponse listResponse = (FtpWebResponse)listRequest.GetResponse()) 
    using (Stream listStream = listResponse.GetResponseStream()) 
    using (StreamReader listReader = new StreamReader(listStream)) 
    { 
     while (!listReader.EndOfStream) 
     { 
      lines.Add(listReader.ReadLine()); 
     } 
    } 

    foreach (string line in lines) 
    { 
     string[] tokens = 
      line.Split(new[] { ' ' }, 9, StringSplitOptions.RemoveEmptyEntries); 
     string name = tokens[8]; 
     string permissions = tokens[0]; 

     string fileUrl = url + name; 

     if (permissions[0] == 'd') 
     { 
      DeleteFtpDirectory(fileUrl + "/", credentials); 
     } 
     else 
     { 
      FtpWebRequest deleteRequest = (FtpWebRequest)WebRequest.Create(fileUrl); 
      deleteRequest.Method = WebRequestMethods.Ftp.DeleteFile; 
      deleteRequest.Credentials = credentials; 

      deleteRequest.GetResponse(); 
     } 
    } 

    FtpWebRequest removeRequest = (FtpWebRequest)WebRequest.Create(url); 
    removeRequest.Method = WebRequestMethods.Ftp.RemoveDirectory; 
    removeRequest.Credentials = credentials; 

    removeRequest.GetResponse(); 
} 

Il url dovrebbe essere come ftp://example.com/directory/to/delete/


o utilizzare una libreria di terze parti che supporta le operazioni ricorsive.

Ad esempio, con WinSCP .NET assembly è possibile eliminare tutta la directory con una singola chiamata a Session.RemoveFiles:

// Setup session options 
SessionOptions sessionOptions = new SessionOptions 
{ 
    Protocol = Protocol.Ftp, 
    HostName = "example.com", 
    UserName = "user", 
    Password = "mypassword", 
}; 

using (Session session = new Session()) 
{ 
    // Connect 
    session.Open(sessionOptions); 

    // Delete folder 
    session.RemoveFiles("/home/user/foldertoremove").Check(); 
} 

Internamente, WinSCP utilizza il comando MLSD, se supportato dal server. In caso contrario, utilizza il comando LIST e supporta dozzine di formati di elenchi diversi.

(Io sono l'autore di WinSCP)

0

Nessuna delle soluzioni davvero lavorato su diversi tipi di server, tranne usando System.Net.FtpClient

using System.Net.FtpClient; 
static void DeleteFtpDirectoryAndContent(string host, string path, NetworkCredential credentials, string dontDeleteFileUrl) 
    { 
     using (FtpClient conn = new FtpClient()) 
     { 
      conn.Host = host; 
      conn.Credentials = credentials; 

      foreach (FtpListItem item in conn.GetListing(path, FtpListOption.AllFiles | FtpListOption.ForceList)) 
      { 

       switch (item.Type) 
       { 
        case FtpFileSystemObjectType.Directory: 
         conn.DeleteDirectory(item.FullName, true, FtpListOption.AllFiles | FtpListOption.ForceList); 
         break; 
        case FtpFileSystemObjectType.File: 
         if (!dontDeleteFileUrl.EndsWith(item.FullName, StringComparison.InvariantCultureIgnoreCase)) 
          conn.DeleteFile(item.FullName); 
         break; 
       } 
      } 

     } 
    } 
Problemi correlati