Как получить размер файла каталогов из протокола FTP в приложении .NET

В настоящее время я делаю небольшое консольное приложение .NET для автоматического резервного копирования некоторых моих файлов на мой сервер. Проблема, с которой я сталкиваюсь, заключается в том, что у меня была плохая погода, которая привела к перебоям в подаче электроэнергии и сети. За это время я заметил, что значительная часть моих файлов не прошла или была повреждена. Мне было интересно, есть ли способ получить размер папки на другом конце и посмотреть, совпадают ли имена файлов, количество файлов и общий размер каталога. Я пробовал WinSCP и NcFTP как способы передачи файлов, но я ничего не видел относительно получения правильного размера файла.

Это в значительной степени передача Windows в Windows, поэтому, если есть аргумент командной строки, который возвращает мне размер через FTP-клиент, это было бы здорово.


person Seb    schedule 25.10.2011    source источник
comment
Почему вы выбрали FTP? Вы открыты для других протоколов?   -  person CodesInChaos    schedule 25.10.2011
comment
В зависимости от других протоколов я могу попробовать. Я только сделал FTP из-за скорости.   -  person Seb    schedule 28.10.2011


Ответы (3)


Не существует стандартного способа запросить «общий размер файлов в этом каталоге». Вы можете запросить размер каждого файла отдельно через SIZE file.txt, или вы можете запросить ls -l всего каталога и проанализировать размеры файлов.

person Raymond Chen    schedule 25.10.2011
comment
Этот метод утомителен для каталогов с большими файлами и попытками разобрать их по сети, но в целом это работает. Спасибо за помощь. - person Seb; 31.10.2011

Стандартной команды FTP для получения размера каталога не существует.

Вы должны рекурсивно перебирать все подкаталоги и файлы и суммировать размеры.

Это непросто с .NET framework/FtpWebRequest, так как он не поддерживает команду MLSD, которая является единственным переносимым способом получения списка каталогов с атрибутами файлов в протоколе FTP.

Все, что вы можете сделать, это использовать команду LIST (ListDirectoryDetails) и попытаться проанализировать листинг для конкретного сервера. Многие FTP-серверы используют список в стиле *nix. Но многие серверы используют другой формат. В следующем примере используется формат *nix:

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

    long result = 0;
    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')
        {
            result += CalculateFtpDirectorySize(fileUrl + "/", credentials);
        }
        else
        {
            result += long.Parse(tokens[4]);
        }
    }

    return result;
}

Используйте это как:

var credentials = new NetworkCredential("username", "password");
long size = CalculateFtpDirectorySize("ftp://ftp.example.com/", credentials);

Если ваш сервер использует формат списка DOS/Windows, см. класс C# для анализа WebRequestMethods.Ftp.ListDirectoryDetails FTP-ответа


В качестве альтернативы вы можете использовать стороннюю реализацию FTP-клиента, которая поддерживает современную команду MLSD.

Например, сборка WinSCP .NET поддерживает это.

И у него даже есть удобный метод Session.EnumerateRemoteFiles, который упрощает вычисление размера каталога:

var files = session.EnumerateRemoteFiles("/", null, EnumerationOptions.AllDirectories);
long size = files.Select(fileInfo => fileInfo.Length).Sum();

Полный код будет выглядеть так:

SessionOptions sessionOptions = new SessionOptions
{
    Protocol = Protocol.Ftp,
    HostName = "ftp.example.com",
    UserName = "username",
    Password = "password",
};

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

    var files = session.EnumerateRemoteFiles("/", null, EnumerationOptions.AllDirectories);
    long size = files.Select(fileInfo => fileInfo.Length).Sum();
}

(я автор WinSCP)

person Martin Prikryl    schedule 04.09.2017

Я думаю, что лучше всего получить полный список файлов, а затем отправлять их по одному. Если во время передачи произойдет сбой соединения, загрузка этого файла не удастся. Если загрузка файла прошла успешно, вы можете удалить это имя файла из списка.

поскольку вы упомянули NET в своих тегах, возможно, вам следует посмотреть здесь для пример того, как это сделать на C#. VB.Net будет похож, но даст вам представление.

Вы можете получить список каталогов, как показано здесь.

person ChrisBD    schedule 26.10.2011