Renci SSH.NET: Как удалить непустую директорию?

Я использую Renci SSH.NET для доступа к файлам и папкам на сервере unix. Я хотел бы удалить все дерево каталогов, указав базовый каталог, но когда я вызываю sftp.DeleteDirectory(destination), этот вызов будет успешным, только если я передам пустой каталог.

Однако я также хотел бы иметь возможность удалять каталоги, содержащие файлы или дополнительные папки. Большинство классов .NET справятся с этим автоматически, как это можно сделать в SSH.NET?


person Erik    schedule 12.04.2016    source источник


Ответы (3)


Библиотека SSH.NET не поддерживает никаких рекурсивных операций. Так что рекурсивное удаление тоже недоступно.

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

private static void DeleteDirectory(SftpClient client, string path)
{
    foreach (SftpFile file in client.ListDirectory(path))
    {
        if ((file.Name != ".") && (file.Name != ".."))
        {
            if (file.IsDirectory)
            {
                DeleteDirectory(client, file.FullName);
            }
            else
            {
                client.DeleteFile(file.FullName);
            }
        }
    }

    client.DeleteDirectory(path);
}

Или используйте другую библиотеку SFTP.

Например, с сборкой WinSCP .NET вы можете использовать _ 3_ метод, который может рекурсивно удалить каталог.

// Setup session options
SessionOptions sessionOptions = new SessionOptions
{
    Protocol = Protocol.Sftp,
    HostName = "example.com",
    UserName = "user",
    Password = "mypassword",
    SshHostKeyFingerprint = "ssh-rsa 2048 xxxxxxxxxxx...="
};

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

    // Delete the directory recursively
    session.RemoveFiles("/directory/to/delete").Check();
}

GUI WinSCP может сгенерировать для вас шаблон кода.

(я автор WinSCP)

person Martin Prikryl    schedule 12.04.2016

Попробуйте выполнить команду в SSH вместо использования sftp rm -rf или rm -r.

Код может выглядеть примерно так:

Renci.SshClient ssh1 = new SshCLient("server","user","password");
ssh1.connect();
ssh1.RunCommand("cd LandingZone;rm -rf <directoryName>");
ssh1.Disconnect();
person Shankar Anumula    schedule 12.04.2016

Вы можете удалить дерево каталогов или файл динамически с помощью библиотеки SSH.NET (независимо от того, пустой это каталог или нет), указав удаленный путь этими двумя методами:

  public bool DeleteRemoteDirectoryRecursive(string RemoteDirectoryPath)
  {
        if (string.IsNullOrEmpty(RemoteDirectoryPath))
        {                
            return false;
        }

        var ConnectionInfo = new ConnectionInfo(this.sftpHost, this.sftpPort, this.sftpUser, new PasswordAuthenticationMethod(this.sftpUser, this.sftpPassword));
        using (var client = new SftpClient(ConnectionInfo))
        {                
            client.Connect();

            if (!client.Exists(RemoteDirectoryPath))
            {                   
                client.Disconnect();
                client.Dispose();
                return false;
            }

            foreach (var file in client.ListDirectory(RemoteDirectoryPath))
            {
                if (file.Name.Equals(".") || file.Name.Equals(".."))
                    continue;

                if (file.IsDirectory)
                {
                    client.Disconnect();
                    DeleteRemoteDirectoryRecursive(file.FullName);
                }
                else
                    client.DeleteFile(file.FullName);
            }

            client.DeleteDirectory(RemoteDirectoryPath);

        }

        return true;
    }

    public bool Remove(string RemotePath)
    {
        bool ReturnResult = false;

        try
        {
            if (string.IsNullOrEmpty(RemotePath))
            {
                return false;
            }

            var ConnectionInfo = new ConnectionInfo(this.sftpHost, this.sftpPort, this.sftpUser, new PasswordAuthenticationMethod(this.sftpUser, this.sftpPassword));
            using (var client = new SftpClient(ConnectionInfo))
            {
                client.Connect();

                if (!client.Exists(RemotePath))
                {
                    client.Disconnect();
                    client.Dispose();
                    return false;
                }

                try
                {
                    //  path is directory
                    client.ChangeDirectory(RemotePath);
                    try
                    {
                        DeleteRemoteDirectoryRecursive(RemotePath);
                        ReturnResult = true;
                    }
                    catch
                    {
                        ReturnResult = false;
                    }

                }
                // path is a file
                catch
                {
                    try
                    {
                        client.DeleteFile(RemotePath);
                        ReturnResult = true;
                    }
                    catch
                    {
                        ReturnResult = false;
                    }
                }
            }
        }
        catch (Exception ex)
        {                
            ReturnResult = false;
        }
        return ReturnResult;
    }
person Daniele Frisenna    schedule 05.12.2018
comment
Хотя ваш код, вероятно, работает, он ужасно неэффективен - вы открываете новое соединение для каждого отдельного каталога. - person Martin Prikryl; 05.12.2018
comment
Плюс почему вы используете ChangeDirectory, чтобы проверить, является ли запись файлом или каталогом в вашем Remove методе? Почему бы вам не использовать file.IsDirectory, как в методе DeleteRemoteDirectoryRecursive? - person Martin Prikryl; 05.12.2018