Directory.Delete не работает. Доступ запрещен, но в Windows Explorer это нормально

Я искал SO, но ничего не нашел.

Почему это не работает?

Directory.Delete(@"E:\3\{90120000-001A-0000-0000-0000000FF1CE}-C");

Над строкой будет выбрано исключение "Доступ запрещен". У меня есть admin rigths, и я могу удалить каталог с Explorer.

Похоже на некоторые запретные символы? но Windows Explorer может справиться с этим. Как я могу удалить каталоги с такими именами?

Ответ 1

Спасибо всем за ваш вклад, это помогает мне быстро найти решение.

Как отметил Фил, "Directory.Delete терпит неудачу, если он есть, независимо от разрешений (см. нижнюю часть msdn.microsoft.com/en-us/library/...)"

Кроме того Невозможно удалить атрибут "Только для чтения" из папки Microsoft говорит:

Возможно, вам не удастся удалить Атрибут "Только для чтения" из папки используя проводник Windows. К тому же, некоторые программы могут отображать ошибку при попытке сохранить файлы в папке.

Заключение: всегда удаляйте все атрибуты dir, файлы, отличные от Normal, перед удалением. Таким образом, под кодом решить проблему:

System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(@"E:\3\{90120000-0021-0000-0000-0000000FF1CE}-C1");

if (dir.Exists)
{
    setAttributesNormal(dir);
    dir.Delete(true);
}

. . .

function setAttributesNormal(DirectoryInfo dir) {
    foreach (var subDir in dir.GetDirectories())
        setAttributesNormal(subDir);
    foreach (var file in dir.GetFiles())
    {
        file.Attributes = FileAttributes.Normal;
    }
}

Ответ 2

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

if (dir.Exists)
    {
        setAttributesNormal(dir);
        dir.Delete(true);
    }    

function setAttributesNormal(DirectoryInfo dir)
    {
        foreach (var subDir in dir.GetDirectories())
        {
            setAttributesNormal(subDir);
            subDir.Attributes = FileAttributes.Normal;
        }
        foreach (var file in dir.GetFiles())
        {
            file.Attributes = FileAttributes.Normal;
        }
    }

Ответ 3

На основе каталога, в котором вы работаете, вам, вероятно, понадобится доступ администратора для удаления файлов. Чтобы проверить это, запустите приложение как администратор из проводника и посмотрите, работает ли он (щелкните правой кнопкой мыши файл .exe и выберите "Запуск от имени администратора" ).

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

<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
  <security>
    <requestedPrivileges>
      <requestedExecutionLevel level="requireAdministrator" />
    </requestedPrivileges>
  </security>
</trustInfo>

Ответ 4

Вы пытались создать новый экземпляр класса DirectoryInfo, а затем проверить существование перед удалением? Код будет выглядеть так:

        System.IO.DirectoryInfo dir = new System.IO.DirectoryInfo(@"E:\3\{90120000-001A-0000-0000-0000000FF1CE}-C");
        if (dir.Exists)
            dir.Delete(true);

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

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

Ответ 5

У меня был этот симптом, и на самом деле это был explorer.exe, который блокировал каталог. Я нашел это с помощью handle.exe, но можно также использовать powershell, чтобы найти, какой процесс блокирует файл:

$lockedFile = "C:\Windows\System32\wshtcpip.dll"
Get-Process | foreach{$processVar = $_; $_.Modules | foreach { if ($_.FileName -like "${lockedFile}*") { $processVar.Name + " PID:" + $processVar.id + " [" + $_.Filename + "]"}}}

Затем вам нужно решить, пытаться ли прекратить этот процесс изящно или нет; было бы легко изменить powershell script, чтобы попытаться убить любые процессы, блокирующие файл:

$lockedFile = "C:\directory_I_want_to_delete"
Get-Process | foreach{$processVar = $_; $_.Modules | foreach { if ($_.FileName -like "${lockedFile}*") { write-host $processVar.Name + " PID:" + $processVar.id + " [" + $_.Filename + "]" ; write-host "Killing process..." ; stop-process -pid $processVar.id -force }}}

Ответ 6

Добавление к @binball и @Chuck ответ. Вот несколько быстрая асинхронная реализация setAttributesNormal() использующая BFS для обхода каталогов. Он идеально подходит для глубокого обхода каталога, где рекурсия может заполнить стек вызовов.

internal static void SetAttributesNormal(DirectoryInfo path) {
    // BFS folder permissions normalizer
    Queue<DirectoryInfo> dirs = new Queue<DirectoryInfo>();
    dirs.Enqueue(path);
    while (dirs.Count > 0) {
        var dir = dirs.Dequeue();
        dir.Attributes = FileAttributes.Normal;
        Parallel.ForEach(dir.EnumerateFiles(), e => e.Attributes = FileAttributes.Normal);
        foreach (var subDir in dir.GetDirectories())
            dirs.Enqueue(subDir);
    }
}