Не удается удалить каталог с помощью Directory.Delete(путь, истина)

Я использую .NET 3.5, пытаясь рекурсивно удалить каталог, используя:

Directory.Delete(myPath, true);

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

Однако иногда я получаю следующее:

System.IO.IOException: The directory is not empty.
    at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
    at System.IO.Directory.DeleteHelper(String fullPath, String userPath, Boolean recursive)
    at System.IO.Directory.Delete(String fullPath, String userPath, Boolean recursive)
    ...

Я не удивлен, что метод иногда бросает, но я удивлен, получив это конкретное сообщение, когда рекурсивная правда. (Я знаю, что каталог не пуст.)

Есть ли причина, по которой я вижу это вместо AccessViolationException?

Ответ 1

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


Я столкнулся с этой проблемой раньше.

Корень проблемы заключается в том, что эта функция не удаляет файлы, находящиеся в структуре каталогов. Так что вам нужно будет создать функцию, которая удалит все файлы в структуре каталогов, а затем все каталоги перед удалением самого каталога. Я знаю, что это противоречит второму параметру, но это гораздо более безопасный подход. Кроме того, вы, вероятно, захотите удалить атрибуты доступа READ-ONLY из файлов непосредственно перед их удалением. В противном случае это приведет к возникновению исключения.

Просто поместите этот код в свой проект.

public static void DeleteDirectory(string target_dir)
{
    string[] files = Directory.GetFiles(target_dir);
    string[] dirs = Directory.GetDirectories(target_dir);

    foreach (string file in files)
    {
        File.SetAttributes(file, FileAttributes.Normal);
        File.Delete(file);
    }

    foreach (string dir in dirs)
    {
        DeleteDirectory(dir);
    }

    Directory.Delete(target_dir, false);
}

Кроме того, для меня я лично добавляю ограничение на области машины, которые разрешены для удаления, потому что вы хотите, чтобы кто-то вызывал эту функцию на C:\WINDOWS (%WinDir%) или C:\.

Ответ 2

Если вы пытаетесь рекурсивно удалить каталог a и каталог a\b открыт в Проводнике, b будет удален, но вы получите, что каталог "ошибка не является" для a, хотя это пустой, когда вы идете и смотрите. Текущая директория любого приложения (включая Explorer) сохраняет дескриптор каталога. Когда вы вызываете Directory.Delete(true), он удаляет снизу вверх: b, затем a. Если в проводнике открыт b, Explorer обнаружит удаление b, сменит каталог вверх cd .. и очистит открытые дескрипторы. Поскольку файловая система работает асинхронно, операция Directory.Delete завершается с ошибкой из-за конфликтов с Explorer.

Неполное решение

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

// incomplete!
try
{
    Directory.Delete(path, true);
}
catch (IOException)
{
    Thread.Sleep(0);
    Directory.Delete(path, true);
}

Но это работает только в том случае, если открытый каталог является непосредственным дочерним элементом каталога, который вы удаляете. Если в проводнике открыт a\b\c\d, и вы используете его на a, этот метод не удастся после удаления d и c.

Несколько лучшее решение

Этот метод будет обрабатывать удаление глубокой структуры каталога, даже если один из каталогов нижнего уровня открыт в Проводнике.

/// <summary>
/// Depth-first recursive delete, with handling for descendant 
/// directories open in Windows Explorer.
/// </summary>
public static void DeleteDirectory(string path)
{
    foreach (string directory in Directory.GetDirectories(path))
    {
        DeleteDirectory(directory);
    }

    try
    {
        Directory.Delete(path, true);
    }
    catch (IOException) 
    {
        Directory.Delete(path, true);
    }
    catch (UnauthorizedAccessException)
    {
        Directory.Delete(path, true);
    }
}

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

Возможно, вы сможете уменьшить количество исключений, которые были выбраны и пойманы при типичных условиях, добавив Thread.Sleep(0) в начале блока try. Кроме того, существует риск того, что при большой нагрузке на систему вы можете пролететь через обе попытки Directory.Delete и выйти из строя. Рассмотрите это решение как отправную точку для более надежного рекурсивного удаления.

Общий ответ

В этом решении рассматриваются только те особенности взаимодействия с проводником Windows. Если вы хотите работать с удаленным удалением, нужно иметь в виду, что все (сканер вирусов и т.д.) Может в любой момент иметь открытый дескриптор того, что вы пытаетесь удалить. Поэтому вы должны попробовать еще раз позже. Сколько позже, и сколько раз вы пытаетесь, зависит от того, насколько важно, чтобы объект был удален. Поскольку MSDN указывает,

Надежный код итерации файлов должен учитывать многие сложности файловой системы.

Этот невинный оператор, содержащий только ссылку на справочную документацию NTFS, должен заставить ваши волосы встать.

( Изменить: много. Этот ответ изначально имел только первое, неполное решение.)

Ответ 3

Прежде чем идти дальше, проверьте следующие причины, которые находятся под вашим контролем:

  • Установлена ​​ли папка как текущий каталог вашего процесса? Если да, сначала измените его на что-то другое.
  • Вы открыли файл (или загрузили DLL) из этой папки? (и забыл закрыть/выгрузить его).

В противном случае проверьте следующие законные причины вне вашего контроля:

  • В этой папке есть файлы, помеченные как доступные только для чтения.
  • У вас нет разрешения на удаление для некоторых из этих файлов.
  • Файл или подпапка открыта в проводнике или другом приложении.

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

Как только вы исключили вышеуказанные причины, все еще есть возможность ложных сбоев. Удаление приведет к сбою, если кто-либо держит дескриптор любого из удаляемых файлов или папок, и есть много причин, по которым кто-то может перечислять папку или читать ее файлы:

  • поисковые индексы
  • антивирусы
  • программное обеспечение для резервного копирования

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

private static void DeleteRecursivelyWithMagicDust(string destinationDir) {
    const int magicDust = 10;
    for (var gnomes = 1; gnomes <= magicDust; gnomes++) {
        try {
            Directory.Delete(destinationDir, true);
        } catch (DirectoryNotFoundException) {
            return;  // good!
        } catch (IOException) { // System.IO.IOException: The directory is not empty
            System.Diagnostics.Debug.WriteLine("Gnomes prevent deletion of {0}! Applying magic dust, attempt #{1}.", destinationDir, gnomes);

            // see http://stackoverflow.com/questions/329355/cannot-delete-directory-with-directory-deletepath-true for more magic
            Thread.Sleep(50);
            continue;
        }
        return;
    }
    // depending on your use case, consider throwing an exception here
}

По-моему, такой помощник должен использоваться для всех удалений, потому что ложные сбои всегда возможны. Тем не менее, ВЫ ДОЛЖНЫ АДАПТИРОВАТЬ ДАННЫЙ КОД К ВАШЕМУ ИСПОЛЬЗОВАНИЮ, а не просто слепо скопировать его.

У меня были ложные сбои для внутренней папки данных, сгенерированной моим приложением, расположенной под% LocalAppData%, поэтому мой анализ выглядит следующим образом:

  • Папка управляется исключительно моим приложением, и у пользователя нет веских причин идти и отмечать вещи как доступные для чтения или недоступные внутри этой папки, поэтому я не пытаюсь обрабатывать этот случай.

  • Там нет ценных созданных пользователем материалов, поэтому нет риска насильственного удаления чего-либо по ошибке.

  • Являюсь внутренней папкой данных, я не ожидаю, что она будет открыта в проводнике, по крайней мере, я не чувствую необходимости конкретно обрабатывать этот случай (т.е. я отлично обрабатываю этот случай с помощью поддержки).

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

  • Я решил ограничить повторы до 500 мс (50 * 10). Это произвольный порог, который работает на практике; Я хотел, чтобы порог был достаточно коротким, чтобы пользователи не убивали приложение, думая, что он перестает отвечать. С другой стороны, полсекунды достаточно времени для того, чтобы преступник закончил обработку моей папки. Судя по другим ответам SO, которые иногда находят даже Sleep(0) приемлемыми, очень немногие пользователи будут испытывать больше, чем один повтор.

  • Я повторяю каждые 50 мс, что является другим произвольным числом. Я чувствую, что если файл обрабатывается (индексируется, проверяется), когда я пытаюсь его удалить, 50 мс - это подходящее время, чтобы ожидать завершения обработки в моем случае. Кроме того, 50 мс достаточно малы, чтобы не привести к заметному замедлению; опять-таки, Sleep(0) во многих случаях оказывается достаточно, поэтому мы не хотим слишком сильно задерживать.

  • Код повторяет любые исключения IO. Обычно я не ожидаю каких-либо исключений, обращающихся к% LocalAppData%, поэтому я выбрал простоту и принял риск задержки 500 мс в случае возникновения законного исключения. Я также не хотел выяснять способ обнаружения точного исключения, которое я хочу повторить.

Ответ 4

У меня была такая же проблема в Delphi. И конечным результатом было то, что моим собственным приложением была блокировка каталога, который я хотел удалить. Каким-то образом каталог был заблокирован, когда я писал ему (некоторые временные файлы).

Ловушка 22 была, я сделал простой каталог изменений для него родительским, прежде чем удалять его.

Ответ 5

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

Process.Start("cmd.exe", "/c " + @"rmdir /s/q C:\Test\TestDirectoryContainingReadOnlyFiles"); 

(Измените бит, чтобы не запускать CMD-окно мгновенно, доступное по всему Интернету)

Ответ 6

Вы можете воспроизвести ошибку, выполнив:

Directory.CreateDirectory(@"C:\Temp\a\b\c\");
Process.Start(@"C:\Temp\a\b\c\");
Thread.Sleep(1000);
Directory.Delete(@"C:\Temp\a\b\c");
Directory.Delete(@"C:\Temp\a\b");
Directory.Delete(@"C:\Temp\a");

При попытке удалить каталог "b" он выбрасывает IOException "Каталог не пуст". Это глупо, поскольку мы просто удалили каталог "c".

По моему мнению, объяснение заключается в том, что каталог 'c' отмечен как удаленный. Но удаление еще не выполнено в системе. Система ответила, что задание выполнено, а на самом деле оно все еще обрабатывается. Система, вероятно, ждет, чтобы проводник файлов сосредоточился на родительском каталоге для фиксации удаления.

Если вы посмотрите на исходный код функции Delete (http://referencesource.microsoft.com/#mscorlib/system/io/directory.cs), вы увидите, что он использует собственную функцию Win32Native.RemoveDirectory. Это поведение do-not-wait отмечено здесь:

Функция RemoveDirectory помечает каталог для удаления при закрытии. Поэтому каталог не удаляется до тех пор, пока последний дескриптор каталога не будет закрыт.

(http://msdn.microsoft.com/en-us/library/windows/desktop/aa365488(v=vs.85).aspx)

Сон и повторение - это решение. Решение ryascl.

Ответ 7

Одна важная вещь, о которой следует упомянуть (я добавил ее в качестве комментария, но мне не разрешено) заключается в том, что поведение перегрузки изменилось с .NET 3.5 на .NET 4.0.

Directory.Delete(myPath, true);

Начиная с .NET 4.0 он удаляет файлы в самой папке, но НЕ в 3.5. Это также можно увидеть в документации MSDN.

.NET 4.0

Удаляет указанный каталог и, если указано, любые подкаталоги и файлы в каталоге.

.NET 3.5

Удаляет пустой каталог и, если указано, любые подкаталоги и файлы в каталоге.

Ответ 8

У меня возникли такие странные проблемы с разрешением, которые удаляют каталоги профилей пользователей (в C:\Documents and Settings), несмотря на то, что они могут сделать это в оболочке Explorer.

File.SetAttributes(target_dir, FileAttributes.Normal);
Directory.Delete(target_dir, false);

Мне не имеет значения, что делает "файл" в каталоге, но я знаю, что он работает и этого достаточно для меня!

Ответ 9

Современный ответ Async

Принятый ответ просто неверен, он может работать для некоторых людей, потому что время, затрачиваемое на получение файлов с диска, освобождает все, что блокировало файлы. Дело в том, что это происходит потому, что файлы блокируются каким-либо другим процессом/потоком/действием. Другие ответы используют Thread.Sleep (Yuck), чтобы повторить попытку удаления каталога через некоторое время. Этот вопрос нуждается в пересмотре с более современным ответом.

public static async Task<bool> TryDeleteDirectory(
   string directoryPath,
   int maxRetries = 10,
   int millisecondsDelay = 30)
{
    if (directoryPath == null)
        throw new ArgumentNullException(directoryPath);
    if (maxRetries < 1)
        throw new ArgumentOutOfRangeException(nameof(maxRetries));
    if (millisecondsDelay < 1)
        throw new ArgumentOutOfRangeException(nameof(millisecondsDelay));

    for (int i = 0; i < maxRetries; ++i)
    {
        try
        {
            if (Directory.Exists(directoryPath))
            {
                Directory.Delete(directoryPath, true);
            }

            return true;
        }
        catch (IOException)
        {
            await Task.Delay(millisecondsDelay);
        }
        catch (UnauthorizedAccessException)
        {
            await Task.Delay(millisecondsDelay);
        }
    }

    return false;
}

Единичные тесты

Эти тесты показывают пример того, как заблокированный файл может привести к сбою Directory.Delete и как выше описанный метод TryDeleteDirectory устраняет проблему.

[Fact]
public async Task TryDeleteDirectory_FileLocked_DirectoryNotDeletedReturnsFalse()
{
    var directoryPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
    var subDirectoryPath = Path.Combine(Path.GetTempPath(), "SubDirectory");
    var filePath = Path.Combine(directoryPath, "File.txt");

    try
    {
        Directory.CreateDirectory(directoryPath);
        Directory.CreateDirectory(subDirectoryPath);

        using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Write))
        {
            var result = await TryDeleteDirectory(directoryPath, 3, 30);
            Assert.False(result);
            Assert.True(Directory.Exists(directoryPath));
        }
    }
    finally
    {
        if (Directory.Exists(directoryPath))
        {
            Directory.Delete(directoryPath, true);
        }
    }
}

[Fact]
public async Task TryDeleteDirectory_FileLockedThenReleased_DirectoryDeletedReturnsTrue()
{
    var directoryPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
    var subDirectoryPath = Path.Combine(Path.GetTempPath(), "SubDirectory");
    var filePath = Path.Combine(directoryPath, "File.txt");

    try
    {
        Directory.CreateDirectory(directoryPath);
        Directory.CreateDirectory(subDirectoryPath);

        Task<bool> task;
        using (var fileStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Write))
        {
            task = TryDeleteDirectory(directoryPath, 3, 30);
            await Task.Delay(30);
            Assert.True(Directory.Exists(directoryPath));
        }

        var result = await task;
        Assert.True(result);
        Assert.False(Directory.Exists(directoryPath));
    }
    finally
    {
        if (Directory.Exists(directoryPath))
        {
            Directory.Delete(directoryPath, true);
        }
    }
}

Ответ 10

Этот ответ основан на: fooobar.com/questions/15783/.... Разница с моим кодом заключается в том, что мы только перезаписываем много удаленных подкаталогов и файлов при необходимости, чтобы вызвать Directory.Delete сбой при первой попытке (что может произойти из-за того, что проводник Windows смотрит в каталог).

    public static void DeleteDirectory(string dir, bool secondAttempt = false)
    {
        // If this is a second try, we are going to manually 
        // delete the files and sub-directories. 
        if (secondAttempt)
        {
            // Interrupt the current thread to allow Explorer time to release a directory handle
            Thread.Sleep(0);

            // Delete any files in the directory 
            foreach (var f in Directory.GetFiles(dir, "*.*", SearchOption.TopDirectoryOnly))
                File.Delete(f);

            // Try manually recursing and deleting sub-directories 
            foreach (var d in Directory.GetDirectories(dir))
                DeleteDirectory(d);

            // Now we try to delete the current directory
            Directory.Delete(dir, false);
            return;
        }

        try
        {
            // First attempt: use the standard MSDN approach.
            // This will throw an exception a directory is open in explorer
            Directory.Delete(dir, true);
        }
        catch (IOException)
        {
            // Try again to delete the directory manually recursing. 
            DeleteDirectory(dir, true);
        }
        catch (UnauthorizedAccessException)
        {
            // Try again to delete the directory manually recursing. 
            DeleteDirectory(dir, true);
        } 
    }

Ответ 11

Я потратил несколько часов на решение этой проблемы и другие исключения при удалении каталога. Это мое решение

 public static void DeleteDirectory(string target_dir)
    {
        DeleteDirectoryFiles(target_dir);
        while (Directory.Exists(target_dir))
        {
            lock (_lock)
            {
                DeleteDirectoryDirs(target_dir);
            }
        }
    }

    private static void DeleteDirectoryDirs(string target_dir)
    {
        System.Threading.Thread.Sleep(100);

        if (Directory.Exists(target_dir))
        {

            string[] dirs = Directory.GetDirectories(target_dir);

            if (dirs.Length == 0)
                Directory.Delete(target_dir, false);
            else
                foreach (string dir in dirs)
                    DeleteDirectoryDirs(dir);
        }
    }

    private static void DeleteDirectoryFiles(string target_dir)
    {
        string[] files = Directory.GetFiles(target_dir);
        string[] dirs = Directory.GetDirectories(target_dir);

        foreach (string file in files)
        {
            File.SetAttributes(file, FileAttributes.Normal);
            File.Delete(file);
        }

        foreach (string dir in dirs)
        {
            DeleteDirectoryFiles(dir);
        }
    }

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

Ответ 12

Рекурсивное удаление каталогов, которое не удаляет файлы, безусловно, неожиданно. Мое исправление для этого:

public class IOUtils
{
    public static void DeleteDirectory(string directory)
    {
        Directory.GetFiles(directory, "*", SearchOption.AllDirectories).ForEach(File.Delete);
        Directory.Delete(directory, true);
    }
}

Я испытал случаи, когда это помогло, но, как правило, Directory.Delete удаляет файлы внутри каталогов при рекурсивном удалении, поскольку задокументирован в msdn.

Время от времени я сталкиваюсь с этим нерегулярным поведением также как и с пользователем Windows Explorer: иногда я не могу удалить папку (он считает, что бессмысленное сообщение "отказано в доступе" ), но когда я разворачиваю и удаляю нижние элементы, я могу затем также удалите верхние элементы. Поэтому я предполагаю, что приведенный выше код касается аномалии ОС - не с проблемой библиотеки базового класса.

Ответ 13

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

Последовательность:

Процесс удаления A:

  • Очистить каталог
  • Удалить (теперь пустой) каталог.

Если кто-то добавляет файл между 1 и 2, то, возможно, 2 выбрал бы указанное исключение?

Ответ 14

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

Ответ 15

Похоже, что наличия пути или подпапки, выбранной в Проводнике Windows, достаточно, чтобы блокировать одно выполнение Directory.Delete(путь, истина), бросая исключение IOEx, как описано выше, и умирает вместо загрузки Windows Explorer в родительскую папку и обрабатывать, как ожидалось.

Ответ 16

У меня была эта проблема сегодня. Это происходило, потому что у меня был проводник окон, открытый для каталога, который пытался быть удален, что вызвало рекурсивный вызов fail и, следовательно, IOException. Убедитесь, что в каталоге нет дескрипторов.

Кроме того, MSDN ясно, что вам не нужно писать свои собственные рекурсии: http://msdn.microsoft.com/en-us/library/fxeahc5f.aspx

Ответ 17

У меня была такая же проблема с Windows Workflow Foundation на сервере сборки с TFS2012. Внутри рабочий процесс называется Directory.Delete() с рекурсивным флагом, установленным в true. В нашем случае это связано с сетью.

Мы удаляли двоичную папку для удаления на сетевом ресурсе перед повторным созданием и повторным заполнением ее новыми бинарниками. Каждая другая сборка потерпит неудачу. При открытии папки сбрасывания после неудачной сборки папка была пуста, что указывает на то, что каждый аспект вызова Directory.Delete() был успешным, за исключением удаления фактического каталога.

Проблема, по-видимому, вызвана асинхронной связью сетевых файлов. Сервер сборки сказал файловому серверу удалить все файлы, и файловый сервер сообщил, что он был, хотя он не был полностью завершен. Затем сервер сборки попросил удалить каталог и файловый сервер отклонил запрос, поскольку он еще не полностью завершил удаление файлов.

Два возможных решения в нашем случае:

  • Создайте рекурсивное удаление в нашем собственном коде с задержками и проверками между каждым шагом
  • Повторите попытку до X раз после исключения IOException, дав задержку перед повторной попыткой

Последний метод быстрый и грязный, но, похоже, делает трюк.

Ответ 18

Это связано с FileChangesNotifications.

Это происходит с ASP.NET 2.0. Когда вы удаляете какую-либо папку в приложении, она перезапускается. Вы сами можете это увидеть, используя Мониторинг работоспособности ASP.NET.

Просто добавьте этот код в свой web.config/configuration/system.web:

<healthMonitoring enabled="true">
  <rules>
    <add name="MyAppLogEvents" eventName="Application Lifetime Events" provider="EventLogProvider" profile="Critical"/>
  </rules>
</healthMonitoring>


После этого проверьте Windows Log -> Application. Что происходит:

При удалении папки, если есть какая-либо подпапка, Delete(path, true) сначала удаляет подпапку. Достаточно, чтобы FileChangesMonitor узнал об удалении и отключении вашего приложения. Тем временем ваш основной каталог еще не удален. Это событие из журнала:


enter image description here


Delete() не завершил свою работу, и поскольку приложение закрывается, возникает исключение:

enter image description here

Если у вас нет подпапок в папке, которую вы удаляете, Delete() просто удаляет все файлы и эту папку, приложение также перезапускается, но вы не выполняете получить любые исключения, потому что перезапуск приложения ничего не прерывает. Но все же вы теряете все сеансы в процессе, приложение не реагирует на запросы при перезапуске и т.д.

Что теперь?

Есть некоторые способы обхода и настройки для отключения этого поведения, Directory Junction, Отключение FCN с реестром, Остановка FileChangesMonitor с использованием Reflection (поскольку нет открытого метода), но все они надевают Кажется, это правильно, потому что FCN существует не просто так. Он ищет структуру вашего приложения, которая не является структурой ваших данных. Короткий ответ: укажите папки, которые вы хотите удалить за пределами вашего приложения. FileChangesMonitor не получит никаких уведомлений, и ваше приложение не будет перезагружаться каждый раз. Вы не получите никаких исключений. Чтобы сделать их видимыми из Интернета, есть два способа:

  • Создайте контроллер, который обрабатывает входящие вызовы, а затем отсылает файлы обратно, читая их из папки вне приложения (вне wwwroot).

  • Если ваш проект большой и производительность важна, настройте отдельный маленький и быстрый веб-сервер для обслуживания статического контента. Таким образом, вы отправите в IIS свою конкретную работу. Он может быть на одной машине (мангуста для Windows) или другой машине (nginx для Linux). Хорошая новость заключается в том, что вам не нужно платить дополнительную лицензию Microsoft для установки статического сервера контента на Linux.

Надеюсь, что это поможет.

Ответ 19

Как упоминалось выше, "принятое" решение терпит неудачу в точках повторной обработки, но люди все еще отмечают его (???). Там гораздо более короткое решение, которое правильно реплицирует функциональность:

public static void rmdir(string target, bool recursive)
{
    string tfilename = Path.GetDirectoryName(target) +
        (target.Contains(Path.DirectorySeparatorChar.ToString()) ? Path.DirectorySeparatorChar.ToString() : string.Empty) +
        Path.GetRandomFileName();
    Directory.Move(target, tfilename);
    Directory.Delete(tfilename, recursive);
}

Я знаю, не обрабатывает случаи разрешений, упомянутые ниже, но для всех целей и задач FAR BETTER предоставляет ожидаемую функциональность исходного/биржевого каталога. Delete() - и с большим количеством меньше кода тоже.

Вы можете безопасно продолжить обработку, потому что старый каталог будет не в порядке... даже если он не ушел, потому что "файловая система все еще догоняет" (или что-то другое, что было предложено MS для обеспечения сломанной функции).

В качестве преимущества, если вы знаете, что ваш целевой каталог большой/глубокий и не хочет ждать (или беспокоиться об исключениях), последняя строка может быть заменена на:

    ThreadPool.QueueUserWorkItem((o) => { Directory.Delete(tfilename, recursive); });

Вы по-прежнему можете продолжать работать.

Ответ 20

Эта проблема может появиться в Windows при наличии файлов в каталоге (или в любом подкаталоге), длина пути которого превышает 260 символов.

В таких случаях вам нужно удалить \\\\?\C:\mydir вместо C:\mydir. О пределе 260 символов вы можете прочитать здесь.

Ответ 21

Невысокие решения для меня хорошо работали. Я закончил с помощью отредактированной версии решения @ryascl, как показано ниже:

    /// <summary>
    /// Depth-first recursive delete, with handling for descendant 
    /// directories open in Windows Explorer.
    /// </summary>
    public static void DeleteDirectory(string path)
    {
        foreach (string directory in Directory.GetDirectories(path))
        {
            Thread.Sleep(1);
            DeleteDir(directory);
        }
        DeleteDir(path);
    }

    private static void DeleteDir(string dir)
    {
        try
        {
            Thread.Sleep(1);
            Directory.Delete(dir, true);
        }
        catch (IOException)
        {
            DeleteDir(dir);
        }
        catch (UnauthorizedAccessException)
        {
            DeleteDir(dir);
        }
    }

Ответ 22

Если текущим каталогом вашего приложения (или любого другого приложения) является тот, который вы пытаетесь удалить, это не будет ошибка нарушения доступа, но каталог не пуст. Убедитесь, что это не ваше собственное приложение, изменив текущий каталог; также убедитесь, что каталог не открыт в какой-либо другой программе (например, Word, excel, Total Commander и т.д.). Большинство программ будут записываться в каталог с открытым файлом, что может привести к этому.

Ответ 23

в случае сетевых файлов Directory.DeleteHelper(рекурсивный: = true) может вызвать IOException, вызванное задержкой удаления файла

Ответ 24

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

Ответ 25

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

Ответ 26

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

// delete any existing update content folder for this update
if (await fileHelper.DirectoryExistsAsync(currentUpdateFolderPath))
       await fileHelper.DeleteDirectoryAsync(currentUpdateFolderPath);

При этом:

bool exists = false;                
if (await fileHelper.DirectoryExistsAsync(currentUpdateFolderPath))
    exists = true;

// delete any existing update content folder for this update
if (exists)
    await fileHelper.DeleteDirectoryAsync(currentUpdateFolderPath);

Вывод? Существует некоторый асинхронный аспект избавления от дескриптора, используемого для проверки существования, с которым Microsoft не могла говорить. Это как если бы асинхронный метод внутри оператора if имел оператор if, действующий как оператор using.

Ответ 27

Ни один из вышеперечисленных ответов не работал у меня. Похоже, что мое собственное использование приложения DirectoryInfo в целевом каталоге вызывало его блокировку.

Принудительная сборка мусора решила проблему, но не сразу. Несколько попыток удалить, если требуется.

Обратите внимание на Directory.Exists, поскольку он может исчезнуть после исключения. Я не знаю, почему удаление для меня было отложено (Windows 7 SP1)

        for (int attempts = 0; attempts < 10; attempts++)
        {
            try
            {
                if (Directory.Exists(folder))
                {
                    Directory.Delete(folder, true);
                }
                return;
            }
            catch (IOException e)
            {
                GC.Collect();
                Thread.Sleep(1000);
            }
        }

        throw new Exception("Failed to remove folder.");

Ответ 28

добавьте true во второй параметр.

Directory.Delete(path, true);

Он удалит все.