Как рекурсивно удалить папку с файлами, используя FtpWebRequest? - PullRequest
6 голосов
/ 01 февраля 2011

Я хочу удалить папку на FTP и ее файлы рекурсивно.

Какой пример кода можно реализовать?

Ответы [ 4 ]

11 голосов
/ 07 января 2014

Сначала вы должны перечислить все ваши файлы в вашем каталоге:

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

Затем вам нужен метод для удаления одного файла (потому что вы можете удалить папку, только если она пуста):

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

И наконец:

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

Вы можете легко назвать это так (для меня эти методы находятся в классе с именем "Ftp"):

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

Конечно, вам нужно настроить эти строки, но у меня это отлично работает:)

5 голосов
/ 02 сентября 2016

Нет рекурсивных операций в классе FtpWebRequest (или в любой другой реализации FTP в .NET Framework).Вы должны реализовать рекурсию самостоятельно:

  • Вывести список удаленных каталогов
  • Повторять записи, удалять файлы и повторять их в подкаталогах (перечислять их снова и т.*

    Сложная задача - определить файлы из подкаталогов.Нет способа сделать это портативным способом с FtpWebRequest.К сожалению, FtpWebRequest не поддерживает команду MLSD, которая является единственным переносимым способом получения списка каталогов с атрибутами файлов в протоколе FTP.См. Также Проверка того, является ли объект на FTP-сервере файлом или каталогом .

    Возможны следующие варианты:

    • Выполнить операцию с именем файла, которая наверняка не будет выполнена.для файла и преуспеть для каталога (или наоборот).Т.е. вы можете попробовать скачать «имя».Если это удается, это файл, если это не удается, это каталог.Но это может стать проблемой производительности, когда у вас есть большое количество записей.
    • Вам может повезти, и в вашем конкретном случае вы можете отличить файл из каталога по имени файла (т.е. все ваши файлыиметь расширение, а подкаталоги - нет)
    • Вы используете длинный список каталогов (LIST command = ListDirectoryDetails метод) и пытаетесь проанализировать список, специфичный для сервера.Многие FTP-серверы используют листинг в стиле * nix, где вы идентифицируете каталог по d в самом начале записи.Но многие серверы используют другой формат.В следующем примере используется этот подход (в формате * nix).
    • В этом конкретном случае вы можете просто попытаться удалить запись в виде файла.Если удаление не удалось, попробуйте перечислить запись как каталог.Если листинг завершается успешно, вы предполагаете, что это папка, и действуйте соответственно.К сожалению, некоторые серверы не выдают ошибку, когда вы пытаетесь перечислить файл.Они просто вернут список с одной записью для файла.
    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();
    }
    

    url должно быть похоже на ftp://example.com/directory/to/delete/


    Или использовать стороннюю библиотеку, которая поддерживает рекурсивные операции.

    Например,с помощью WinSCP .NET сборки вы можете удалить весь каталог с помощью одного вызова 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();
    } 
    

    Внутренне WinSCP использует команду MLSD,если поддерживается сервером.Если нет, он использует команду LIST и поддерживает десятки различных форматов листинга.

    (я автор WinSCP)

0 голосов
/ 29 сентября 2016

Ни одно из решений действительно не работало на разных типах серверов, кроме как с использованием 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;
                }
            }

        }
    }
0 голосов
/ 02 февраля 2011

Хороший маленький пример, который вы можете найти здесь:

http://msdn.microsoft.com/en-us/library/system.net.ftpwebrequest.aspx

В примере они использовали класс WebRequestMethods.Ftp.UploadFile, чтобы указать, какую операцию они хотят выполнить.

Используйте метод WebRequestMethods.Ftp.RemoveDirectory, если у вас есть дескриптор родительского каталога, который вы хотите удалить:

http://msdn.microsoft.com/en-us/library/system.net.webrequestmethods.ftp.aspx

...