Удалить все папки и подкаталоги, которые не имеют файла с определенным расширением

Я использую это решение, чтобы удалить все пустые папки и подкаталоги по определенному пути:

static void Main(string[] args)
{
    processDirectory(@"c:\temp");
}

private static void processDirectory(string startLocation)
{
    foreach (var directory in Directory.GetDirectories(startLocation))
    {
        processDirectory(directory);
        if (Directory.GetFiles(directory).Length == 0 && 
            Directory.GetDirectories(directory).Length == 0)
        {
            Directory.Delete(directory, false);
        }
    }
}

Работает отлично. Но я хочу удалить все пустые папки, а также папки, которые не являются пустыми, но также не содержат файлов с .dvr расширение.

Например, в моей папке есть файлы:

Войти

b.log

c.dvr

d.dat

Поэтому эту папку нельзя удалить, поскольку она содержит файл с расширением DVR.

Как я могу отфильтровать это? (Я использую GTK#, но я верю, что код C# будет работать, так как это решение - код C#)

3 ответа

Решение

К сожалению, обработка ошибок очень исключительная, основанная на операциях ввода-вывода. И Directory.Delete создает IOException, если каталог не пустой. Поэтому вам придется удалить файлы вручную:

private static bool processDirectory(string startLocation)
{
    bool result = true;
    foreach (var directory in Directory.GetDirectories(startLocation))
    {
        bool directoryResult = processDirectory(directory);
        result &= directoryResult;

        if (Directory.GetFiles(directory, "*.dvr").Any())
        {
             result = false;
             continue;
        }

        foreach(var file in Directory.GetFiles(directory))
        {
            try
            {
               File.Delete(file);
            }
            catch(IOException)
            {
               // error handling
               result = directoryResult = false;
            }
        }

        if (!directoryResult) continue;
        try
        {
            Directory.Delete(directory, false);
        }
        catch(IOException)
        {
            // error handling
            result = false;
        }
    }

    return result;
}

Я бы использовал Directory.EnumerateFiles, чтобы увидеть, содержит ли каталог искомый файл. Изменение вашего кода на:

static void Main(string[] args)
{
    processDirectory(@"c:\temp");
}

private static void processDirectory(string startLocation)
{
    foreach (var directory in Directory.GetDirectories(startLocation))
    {
        processDirectory(directory);
        if (Directory.GetDirectories(directory).Length == 0  ||
            Directory.EnumerateFiles(directory, "*.dvr").Length == 0
            )
        {
            Directory.Delete(directory, false);
        }
    }
}

Ответ Avitus правильный, но так как он нужен для работы в.NET 2.0, вы не можете использовать EnumerateFiles метод, однако GetFiles хорошо справляется со своей работой Но требует немного больше кода.

Пример:

static void Main(string[] args)
{
    processDirectory(@"c:\temp");
}

private static void processDirectory(string startLocation)
{
    foreach (var directory in Directory.GetDirectories(startLocation))
    {
        processDirectory(directory);

        if (Directory.GetDirectories(directory).Length == 0))
        {
            bool delete = false;

            var files = Directory.GetFiles(directory);
            // This will delete the directory if it contains a file with the Extension
            // of .dvr, regardless if there are other files in there. Might be something you want to change.
            for (int i = 0; i < files.Length && !delete; i++)
            {
                delete = files[i].Extension.Equals(".dvr", StringComparison.OrdinalIgnoreCase);
            }

            if (delete)
            {
                // Recursive must be set to true in order to
                // delete files and sub-directories in the folder.
                // This folder will not have any sub-directories
                // so it's only used to delete the files.
                Directory.Delete(directory, /*recursive*/ true);
            }
        }
    }
}

Вы могли бы, в духе меньшего кода переместить Directory.Delete вызов метода в пределах for цикл, если вы хотите, а затем разорвать цикл.

Другие вопросы по тегам