Tidak dapat menghapus direktori dengan Directory.Delete (path, true)

383

Saya menggunakan .NET 3.5, mencoba menghapus direktori secara rekursif menggunakan:

Directory.Delete(myPath, true);

Pemahaman saya adalah bahwa ini harus dibuang jika file sedang digunakan atau ada masalah izin, tetapi jika tidak maka akan menghapus direktori dan semua isinya.

Namun, saya sesekali mendapatkan ini:

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)
    ...

Saya tidak terkejut bahwa metode ini kadang-kadang melempar, tetapi saya terkejut mendapatkan pesan khusus ini ketika rekursif benar. (Saya tahu direktori ini tidak kosong.)

Apakah ada alasan saya melihat ini alih-alih AccessViolationException?

Jason Anderson
sumber
13
Anda tidak akan melihat AccessViolationException - itu untuk operasi pointer yang tidak valid, bukan untuk akses disk.
Joe White
1
Sepertinya ini semacam masalah IO selain dari direktori yang tidak kosong, seperti pegangan file terbuka atau semacamnya. Saya akan mencoba menggunakan opsi hapus rekursif, kemudian menangkap IOException, mencari dan menutup semua pegangan file yang terbuka, lalu coba lagi. Ada diskusi tentang hal itu di sini: stackoverflow.com/questions/177146/…
Dan Csharpster

Jawaban:

231

Catatan editor: Meskipun jawaban ini mengandung beberapa informasi yang bermanfaat, sebenarnya tidak benar tentang cara kerjanya Directory.Delete. Silakan baca komentar untuk jawaban ini, dan jawaban lain untuk pertanyaan ini.


Saya mengalami masalah ini sebelumnya.

Akar masalahnya adalah bahwa fungsi ini tidak menghapus file yang ada dalam struktur direktori. Jadi yang perlu Anda lakukan adalah membuat fungsi yang menghapus semua file dalam struktur direktori lalu semua direktori sebelum menghapus direktori itu sendiri. Saya tahu ini bertentangan dengan parameter kedua tetapi ini merupakan pendekatan yang jauh lebih aman. Selain itu, Anda mungkin ingin menghapus atribut akses READ-ONLY dari file tepat sebelum Anda menghapusnya. Kalau tidak, itu akan menimbulkan pengecualian.

Cukup masukkan kode ini ke proyek Anda.

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);
}

Juga, bagi saya, saya pribadi menambahkan batasan pada area mesin yang diizinkan untuk dihapus karena Anda ingin seseorang memanggil fungsi ini pada C:\WINDOWS (%WinDir%)atau C:\.

Jeremy Edwards
sumber
117
Ini tidak masuk akal. Directory.Delete (myPath, true) adalah kelebihan yang menghapus semua file yang ada dalam struktur direktori. Jika Anda ingin salah, salah dengan jawaban Ryan S.
Sig. Tolleranza
35
+1 karena walaupun Directory.Delete () menghapus file di dalam subdirektori (dengan rekursif = true), ia melempar "IOException: Directory tidak kosong" jika salah satu dari sub-direktori atau file hanya-baca. Jadi solusi ini berfungsi lebih baik daripada Directory.Delete ()
Anthony Brien
17
Pernyataan Anda yang Directory.Delete(path, true)tidak menghapus file salah. Lihat MSDN msdn.microsoft.com/en-us/library/fxeahc5f.aspx
Konstantin Spirin
20
-1 Dapatkah seseorang tolong beri tanda yang jelas bahwa validitas pendekatan ini sangat diragukan. Jika Directory.Delete(string,bool)gagal, ada sesuatu yang terkunci atau salah kirim dan tidak ada satu ukuran yang cocok untuk semua solusi untuk masalah seperti itu. Orang-orang perlu mengatasi masalah itu dalam konteks mereka dan kami tidak akan menumbuhkan setiap ide pada masalah (dengan mencoba ulang dan menelan) dan berharap untuk hasil yang baik.
Ruben Bartelink
37
Waspadalah terhadap pendekatan ini jika direktori Anda menghapus Anda memiliki pintasan / tautan simbolis ke folder lain - Anda mungkin akhirnya menghapus lebih dari yang Anda harapkan
Chanakya
182

Jika Anda mencoba untuk menghapus direktori adan direktori a\bterbuka di Explorer secara rekursif , bakan dihapus tetapi Anda akan mendapatkan kesalahan 'direktori tidak kosong' karena awalaupun itu kosong ketika Anda pergi dan melihat. Direktori saat ini dari aplikasi apa pun (termasuk Explorer) mempertahankan pegangan ke direktori . Saat Anda menelepon Directory.Delete(true), itu dihapus dari bawah ke atas:, blalu a. Jika bterbuka di Explorer, Explorer akan mendeteksi penghapusan b, ubah direktori ke atas cd ..dan bersihkan pegangan yang terbuka. Karena sistem file beroperasi secara tidak sinkron, Directory.Deleteoperasi gagal karena konflik dengan Explorer.

Solusi tidak lengkap

Saya awalnya memposting solusi berikut, dengan ide untuk mengganggu utas saat ini untuk memungkinkan waktu Explorer untuk melepaskan pegangan direktori.

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

Tetapi ini hanya berfungsi jika direktori terbuka adalah anak langsung dari direktori yang Anda hapus. Jika a\b\c\dterbuka di Explorer dan Anda menggunakan ini a, teknik ini akan gagal setelah menghapus ddan c.

Solusi yang agak lebih baik

Metode ini akan menangani penghapusan struktur direktori yang dalam bahkan jika salah satu direktori tingkat bawah terbuka di Explorer.

/// <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);
    }
}

Terlepas dari pekerjaan ekstra berulang pada kita sendiri, kita masih harus menangani UnauthorizedAccessExceptionyang dapat terjadi di sepanjang jalan. Tidak jelas apakah upaya penghapusan pertama membuka jalan untuk yang kedua, yang berhasil, atau apakah itu hanya penundaan waktu yang diperkenalkan oleh melempar / menangkap pengecualian yang memungkinkan sistem file untuk mengejar ketinggalan.

Anda mungkin dapat mengurangi jumlah pengecualian yang dilemparkan dan ditangkap dalam kondisi umum dengan menambahkan a Thread.Sleep(0)di awal tryblok. Selain itu, ada risiko bahwa di bawah beban sistem yang berat, Anda dapat terbang melalui kedua Directory.Deleteupaya dan gagal. Pertimbangkan solusi ini sebagai titik awal untuk penghapusan rekursif yang lebih kuat.

Jawaban umum

Solusi ini hanya membahas kekhasan berinteraksi dengan Windows Explorer. Jika Anda ingin operasi penghapusan yang sangat rumit, satu hal yang perlu diingat adalah bahwa apa pun (pemindai virus, apa pun) dapat memiliki pegangan terbuka terhadap apa yang Anda coba hapus, kapan saja. Jadi, Anda harus mencoba lagi nanti. Berapa lama kemudian, dan berapa kali Anda mencoba, tergantung pada seberapa penting benda itu dihapus. Seperti yang ditunjukkan MSDN ,

Kode iterasi file yang kuat harus memperhitungkan banyak kompleksitas sistem file.

Pernyataan tidak bersalah ini, yang disediakan hanya dengan tautan ke dokumentasi referensi NTFS, harus membuat rambut Anda berdiri.

( Sunting : Banyak. Jawaban ini awalnya hanya memiliki solusi pertama dan tidak lengkap.)

ryscl
sumber
11
Itu muncul memanggil Directory.Delete (path, true) sementara path atau salah satu folder / file di bawah path terbuka atau dipilih di Windows Explorer akan melempar IOException. Menutup Windows Explorer dan menjalankan kembali kode saya yang ada tanpa coba-coba yang disarankan di atas berfungsi dengan baik.
David Alpert
1
Saya tidak dapat memahami bagaimana dan mengapa ia bekerja tetapi itu bekerja untuk saya sementara mengatur atribut file dan menulis fungsi rekursif saya sendiri tidak.
Stilgar
1
@CarlosLiu Karena itu memberi "Explorer kesempatan untuk melepaskan pegangan direktori"
Dmitry Gonchar
4
Apa yang terjadi adalah bahwa sistem meminta Explorer untuk "melepaskan pegangan direktori", kemudian mencoba untuk menghapus direktori. Jika pegangan direktori tidak dihapus pada waktunya, pengecualian akan muncul dan catchblok dijalankan (sementara itu, Explorer masih merilis direktori, karena tidak ada perintah yang dikirim untuk memberi tahu tidak melakukannya). Panggilan ke Thread.Sleep(0)mungkin atau mungkin tidak perlu, karena catchblok telah memberi sistem sedikit lebih banyak waktu, tetapi memang memberikan sedikit keamanan ekstra dengan biaya rendah. Setelah itu, Deletedisebut, dengan direktori yang sudah dirilis.
Zachary Kniebel
1
@ PandaWood sebenarnya hanya Tidur ini (100) yang bekerja untuk saya. Tidur (0) tidak berhasil. Saya tidak tahu apa yang sedang terjadi dan bagaimana menyelesaikannya dengan benar. Maksud saya, bagaimana jika itu tergantung pada beban server dan di masa depan harus ada 300 atau 400? Bagaimana mengetahuinya? Harus ada cara lain yang tepat ...
Roman
43

Sebelum melangkah lebih jauh, periksa alasan berikut yang berada di bawah kendali Anda:

  • Apakah folder ditetapkan sebagai direktori saat ini dari proses Anda? Jika ya, ubah ke yang lain dulu.
  • Sudahkah Anda membuka file (atau memuat DLL) dari folder itu? (dan lupa menutup / membongkar itu)

Jika tidak, periksa alasan sah berikut di luar kendali Anda:

  • Ada file yang ditandai sebagai hanya-baca di folder itu.
  • Anda tidak memiliki izin penghapusan untuk beberapa file tersebut.
  • File atau subfolder terbuka di Explorer atau aplikasi lain.

Jika salah satu di atas adalah masalahnya, Anda harus memahami mengapa itu terjadi sebelum mencoba meningkatkan kode penghapusan Anda. Haruskah aplikasi Anda menghapus file read-only atau tidak dapat diakses? Siapa yang menandai mereka seperti itu, dan mengapa?

Setelah Anda mengesampingkan alasan di atas, masih ada kemungkinan kegagalan palsu. Penghapusan akan gagal jika ada yang memegang pegangan pada file atau folder yang sedang dihapus, dan ada banyak alasan mengapa seseorang mungkin menghitung folder atau membaca file-nya:

  • pengindeks pencarian
  • anti-virus
  • perangkat lunak cadangan

Pendekatan umum untuk mengatasi kegagalan palsu adalah mencoba beberapa kali, berhenti di antara upaya. Anda jelas tidak ingin terus mencoba selamanya, jadi Anda harus menyerah setelah beberapa upaya dan melemparkan pengecualian atau mengabaikan kesalahan. Seperti ini:

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
}

Menurut pendapat saya, pembantu seperti itu harus digunakan untuk semua penghapusan karena kegagalan palsu selalu mungkin terjadi. Namun, ANDA HARUS MENYESUAIKAN KODE INI UNTUK KASUS PENGGUNAAN ANDA, bukan hanya menyalinnya secara membabi buta.

Saya mengalami kegagalan palsu untuk folder data internal yang dihasilkan oleh aplikasi saya, terletak di bawah% LocalAppData%, jadi analisis saya seperti ini:

  1. Folder dikontrol hanya oleh aplikasi saya, dan pengguna tidak memiliki alasan yang sah untuk pergi dan menandai hal-hal sebagai read-only atau tidak dapat diakses di dalam folder itu, jadi saya tidak mencoba untuk menangani kasus itu.

  2. Tidak ada barang berharga buatan pengguna di sana, jadi tidak ada risiko menghapus sesuatu dengan paksa.

  3. Menjadi folder data internal, saya tidak berharap itu akan terbuka di explorer, setidaknya saya tidak merasa perlu untuk secara khusus menangani kasus ini (yaitu saya baik-baik saja menangani kasus itu melalui dukungan).

  4. Jika semua upaya gagal, saya memilih untuk mengabaikan kesalahan. Kasus terburuk, aplikasi gagal membongkar beberapa sumber daya yang lebih baru, lumpuh dan meminta pengguna untuk menghubungi dukungan, yang dapat diterima oleh saya selama itu tidak sering terjadi. Atau, jika aplikasi tidak macet, itu akan meninggalkan beberapa data lama, yang lagi-lagi dapat saya terima.

  5. Saya memilih untuk membatasi coba lagi hingga 500 ms (50 * 10). Ini adalah ambang batas arbitrer yang berfungsi dalam praktik; Saya ingin ambang batas menjadi cukup pendek sehingga pengguna tidak akan membunuh aplikasi, berpikir bahwa itu telah berhenti merespons. Di sisi lain, setengah detik adalah banyak waktu bagi pelaku untuk menyelesaikan pemrosesan folder saya. Menilai dari jawaban SO lainnya yang kadang-kadang bahkan Sleep(0)bisa diterima, sangat sedikit pengguna yang akan mengalami lebih dari satu coba lagi.

  6. Saya coba lagi setiap 50 ms, yang merupakan nomor sewenang-wenang lainnya. Saya merasa bahwa jika suatu file sedang diproses (diindeks, diperiksa) ketika saya mencoba untuk menghapusnya, 50ms adalah waktu yang tepat untuk mengharapkan pemrosesan selesai dalam kasus saya. Juga, 50 ms cukup kecil untuk tidak menghasilkan penurunan yang nyata; lagi, Sleep(0)tampaknya cukup dalam banyak kasus, jadi kami tidak ingin menunda terlalu banyak.

  7. Kode ini mencoba lagi pada pengecualian IO apa pun. Saya biasanya tidak mengharapkan pengecualian mengakses% LocalAppData%, jadi saya memilih kesederhanaan dan menerima risiko keterlambatan 500 ms jika terjadi pengecualian yang sah. Saya juga tidak ingin mencari cara untuk mendeteksi pengecualian yang tepat yang ingin saya coba lagi.

Andrey Tarantsov
sumber
7
PPS Beberapa bulan kemudian, saya senang melaporkan bahwa ini (agak gila) kode telah sepenuhnya menyelesaikan masalah. Permintaan dukungan tentang masalah ini turun ke nol (dari sekitar 1-2 per minggu).
Andrey Tarantsov
1
+0 Sementara ini lebih kuat dan lebih sedikit 'ini dia; solusi sempurna untuk Anda daripada stackoverflow.com/a/7518831/11635 , bagi saya hal yang sama berlaku - pemrograman secara kebetulan - tangani dengan hati-hati. Satu poin berguna yang terkandung dalam kode Anda adalah bahwa jika Anda akan mencoba ulang, Anda perlu mempertimbangkan bahwa Anda berada dalam perlombaan dengan ambiguitas apakah Direktori telah 'Lenyap' sejak upaya terakhir [dan seorang Directory.Existspenjaga yang naif akan tidak menyelesaikannya.]
Ruben Bartelink
1
Menyukainya ... tidak tahu apa yang saya lakukan bahwa ini selalu menjadi titik sakit bagi saya ... tapi itu bukan karena saya memiliki direktori terbuka di penjelajah ... tidak banyak kegemparan di internet tentang ini lebih -atau kurang bug ... setidaknya aku dan Andrey punya cara untuk menghadapinya :)
TCC
2
@RubenBartelink OK, jadi saya pikir kita bisa sepakat tentang ini: memposting sepotong kode yang berfungsi untuk satu aplikasi tertentu (dan tidak pernah dimaksudkan untuk cocok untuk setiap kasus) karena jawaban SO akan menjadi kerugian bagi banyak pemula dan / atau pengembang bodoh. Saya memberikannya sebagai titik awal untuk penyesuaian, tetapi ya, beberapa orang akan menggunakannya sebagaimana adanya, dan itu hal yang buruk.
Andrey Tarantsov
2
@nopara Anda tidak perlu perbandingan; jika kita keluar dari loop, kita gagal. Dan ya, dalam banyak kasus Anda ingin membuang pengecualian, lalu menambahkan kode penanganan kesalahan yang sesuai ke tumpukan, kemungkinan dengan pesan yang terlihat oleh pengguna.
Andrey Tarantsov
18

Jawaban Async Modern

Jawaban yang diterima benar-benar salah, mungkin berhasil bagi sebagian orang karena waktu yang dibutuhkan untuk mendapatkan file dari disk membebaskan apa pun yang mengunci file. Faktanya adalah, ini terjadi karena file dikunci oleh beberapa proses / aliran / tindakan lainnya. Jawaban lain menggunakan Thread.Sleep(Yuck) untuk mencoba lagi menghapus direktori setelah beberapa waktu. Pertanyaan ini perlu ditinjau kembali dengan jawaban yang lebih modern.

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;
}

Tes Unit

Pengujian ini menunjukkan contoh bagaimana file yang terkunci dapat menyebabkan Directory.Deletekegagalan dan bagaimana TryDeleteDirectorymetode di atas memperbaiki masalah.

[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);
        }
    }
}
Muhammad Rehan Saeed
sumber
Bisakah Anda memperluas apa yang Anda maksud dengan "modern"? Apa manfaat dari pendekatan Anda? Mengapa yang lain, menurut Anda salah?
TinyRacoon
1
Yang lain tidak salah. Mereka hanya menggunakan API lama seperti Thread.Sleepyang harus Anda hindari hari ini dan gunakan async/ awaitdengan Task.Delaysebagai gantinya. Itu bisa dimengerti, ini pertanyaan yang sangat lama.
Muhammad Rehan Saeed
Pendekatan ini tidak akan berfungsi di VB.Net (setidaknya tidak dengan konversi baris per baris yang sangat literal) karenaBC36943 'Await' cannot be used inside a 'Catch' statement, a 'Finally' statement, or a 'SyncLock' statement.
amonroejj
@amonroejj Anda harus menggunakan versi yang lebih lama. Itu sudah diperbaiki.
Muhammad Rehan Saeed
Sedikit perbaikan alih-alih mengembalikan true if (!Directory.Exists(directoryPath)) { return true; } await Task.Delay(millisecondsDelay); untuk menunggu hingga direktori benar-benar hilang
fuchs777
16

Satu hal penting yang harus disebutkan (saya menambahkannya sebagai komentar tapi saya tidak diizinkan) adalah bahwa perilaku overload berubah dari .NET 3.5 ke .NET 4.0.

Directory.Delete(myPath, true);

Mulai dari. NET 4.0 menghapus file dalam folder itu sendiri tetapi TIDAK dalam 3,5. Ini dapat dilihat dalam dokumentasi MSDN juga.

.NET 4.0

Menghapus direktori yang ditentukan dan, jika ditunjukkan, subdirektori dan file apa pun di direktori.

.NET 3.5

Menghapus direktori kosong dan, jika ditunjukkan, subdirektori dan file apa pun di direktori.

Jettatore
sumber
3
Saya pikir ini hanya perubahan dokumentasi ... jika hanya menghapus "direktori kosong", apa artinya menghapus juga file dalam direktori, dengan parameter 2 °? Jika kosong tidak ada file ...
Pisu
Saya khawatir Anda salah mengira. Saya telah memposting ini setelah menguji kode dengan kedua versi kerangka kerja. Menghapus folder yang tidak kosong dalam 3,5 akan menimbulkan pengecualian.
jettatore
15

Saya memiliki masalah yang sama di bawah Delphi. Dan hasil akhirnya adalah aplikasi saya sendiri mengunci direktori yang ingin saya hapus. Entah bagaimana direktori itu terkunci ketika saya menulisnya (beberapa file sementara).

Tangkapan 22 adalah, saya membuat direktori perubahan sederhana untuk orang tuanya sebelum menghapusnya.

Drejc
sumber
6
+1 Sekarang ada sesuatu yang disebutkan oleh msdn untuk Directory.Delete !
Ruben Bartelink
3
ada solusi akhir dengan sampel kode sumber lengkap yang bisa mengatasinya?
Kiquenet
11

Saya terkejut bahwa tidak ada yang memikirkan metode non-rekursif sederhana ini, yang dapat menghapus direktori yang berisi file read only, tanpa perlu mengubah atribut read only dari masing-masingnya.

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

(Ubah sedikit untuk tidak mengaktifkan jendela cmd untuk sementara, yang tersedia di internet)

Piyush Soni
sumber
Senang berbagi dengan kami, tetapi apakah Anda akan berbaik hati memasukkan sedikit perubahan yang diperlukan untuk mencegah penembakan jendela cmd, alih-alih meminta kami untuk mencarinya di internet?
ThunderGr
Ini tidak berhasil. Dalam situasi yang sama di mana saya dapat menghapus file dari command prompt atau Explorer, menggunakan kode ini untuk memanggil rmdir memberikan kode keluar 145 yang diterjemahkan menjadi "Direktori tidak kosong". Itu meninggalkan direktori kosong tetapi masih di tempat juga, persis seperti Directory.Delete ("", true)
Kevin Coulombe
@Kevin Coulombe, Humm ... Apakah Anda yakin menggunakan / s / q switch?
Piyush Soni
1
@KevinCoulombe: Ya, itu pasti komponen COM itu. Ketika saya mencoba melalui C # lama, itu berfungsi dan itu menghapus direktori bersama dengan file di dalamnya (hanya baca atau yang tidak hanya baca).
Piyush Soni
5
Jika Anda mulai mengandalkan komponen eksternal untuk apa yang seharusnya ada dalam kerangka kerja maka itu adalah ide "kurang ideal" karena itu tidak portabel lagi (atau lebih sulit). Bagaimana jika exe tidak ada di sana? Atau opsi / berubah? Jika solusi oleh Jeremy Edwards berfungsi maka itu harus lebih disukai IMHO
frenchone
11

Anda dapat mereproduksi kesalahan dengan menjalankan:

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");

Ketika mencoba menghapus direktori 'b', ia melempar IOException "Direktori tidak kosong". Itu bodoh karena kami baru saja menghapus direktori 'c'.

Dari pemahaman saya, penjelasannya adalah direktori 'c' dicap sebagai dihapus. Namun penghapusan belum dilakukan dalam sistem. Sistem telah menjawab bahwa pekerjaan sudah selesai, padahal nyatanya masih diproses. Sistem mungkin menunggu file explorer fokus pada direktori induk untuk melakukan penghapusan.

Jika Anda melihat kode sumber fungsi Delete ( http://referencesource.microsoft.com/#mscorlib/system/io/directory.cs ) Anda akan melihatnya menggunakan fungsi Win32Native.RemoveDirectory asli. Perilaku tidak-menunggu ini dicatat di sini:

Fungsi RemoveDirectory menandai direktori untuk dihapus saat ditutup. Oleh karena itu, direktori tidak dihapus sampai pegangan terakhir ke direktori ditutup.

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

Tidur dan coba lagi adalah solusinya. Cf solusi ryascl.

Olivier de Rivoyre
sumber
8

Saya punya masalah izin aneh menghapus direktori Profil Pengguna (dalam C: \ Documents and Settings) meskipun mampu melakukannya di shell Explorer.

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

Tidak masuk akal bagi saya apa yang dilakukan oleh operasi "file" pada direktori, tetapi saya tahu itu berfungsi dan itu cukup bagi saya!

p.campbell
sumber
2
Masih tidak ada harapan, ketika direktori memiliki banyak file dan Explorer membuka folder yang berisi file-file itu.
melihat
3

Jawaban ini didasarkan pada: https://stackoverflow.com/a/1703799/184528 . Perbedaannya dengan kode saya, adalah bahwa kita hanya berulang-ulang menghapus banyak sub-direktori dan file ketika perlu panggilan ke Directory.Delete gagal pada upaya pertama (yang dapat terjadi karena windows explorer melihat direktori).

    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);
        } 
    }
cdiggins
sumber
Jadi bagaimana seharusnya menghapus folder jika ada UnauthorizedAccessException? Itu hanya akan melempar, lagi. Dan lagi. Dan lagi ... Karena setiap kali akan pergi ke catchdan memanggil fungsi lagi. A Thread.Sleep(0);tidak mengubah izin Anda. Seharusnya hanya mencatat kesalahan dan gagal dengan anggun, pada saat itu. Dan loop ini hanya akan terus berlanjut selama direktori (sub-) terbuka - itu tidak menutupnya secara terprogram. Apakah kita siap membiarkannya melakukan ini selama hal-hal itu dibiarkan terbuka? Apakah ada cara yang lebih baik?
vapcguy
Jika ada UnauthorizedAccessExceptionmaka secara manual akan mencoba untuk menghapus setiap file secara manual. Jadi itu terus membuat kemajuan dengan melintasi ke dalam struktur direktori. Ya, berpotensi setiap file dan direktori akan melempar pengecualian yang sama, tetapi ini juga dapat terjadi hanya karena penjelajah memegang pegangan untuk itu (lihat stackoverflow.com/a/1703799/184528 ) Saya akan mengubah "tryAgain" menjadi "secondTry" untuk membuatnya lebih jelas.
cdiggins
Untuk menjawab lebih berhasil, ia meneruskan "true" dan mengeksekusi jalur kode yang berbeda.
cdiggins
Benar, melihat hasil edit Anda, tetapi poin saya bukan tentang penghapusan file, tetapi dengan penghapusan direktori. Saya menulis beberapa kode di mana saya bisa melakukan dasarnya Process.Kill()pada setiap proses file dapat dikunci, dan menghapus file. Masalah yang saya hadapi adalah ketika menghapus direktori di mana salah satu file itu masih terbuka (lihat stackoverflow.com/questions/41841590/… ). Jadi kembali melalui loop ini, tidak peduli apa lagi yang dilakukannya, jika ia lakukan Directory.Delete()pada folder itu lagi, itu akan tetap gagal jika pegangan itu tidak dapat dilepaskan.
vapcguy
Dan hal yang sama akan terjadi untuk UnauthorizedAccessExceptionmenghapus file (dengan asumsi ini bahkan diizinkan, karena untuk mendapatkan kode itu gagal Directory.Delete()) tidak secara ajaib memberi Anda izin untuk menghapus direktori.
vapcguy
3

Solusi di atas tidak bekerja dengan baik untuk saya. Saya berakhir dengan menggunakan versi yang sudah diedit dari solusi @ryascl seperti di bawah ini:

    /// <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);
        }
    }
cahit beyaz
sumber
2

Apakah mungkin Anda memiliki kondisi balapan di mana utas atau proses lain menambahkan file ke direktori:

Urutannya adalah:

Deleter proses A:

  1. Kosongkan direktori
  2. Hapus direktori (sekarang kosong).

Jika orang lain menambahkan file antara 1 & 2, maka mungkin 2 akan membuang pengecualian yang terdaftar?

Douglas Leeder
sumber
2

Saya telah menghabiskan beberapa jam untuk menyelesaikan masalah ini dan pengecualian lain dengan menghapus direktori. Ini solusi saya

 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);
        }
    }

Kode ini memiliki penundaan kecil, yang tidak penting untuk aplikasi saya. Tapi hati-hati, penundaan mungkin menjadi masalah bagi Anda jika Anda memiliki banyak subdirektori di dalam direktori yang ingin Anda hapus.

Demid
sumber
8
-1 Apa keterlambatannya? Tolong, jangan pemrograman tanpa sengaja!
Ruben Bartelink
1
@ Ruben Saya tidak mengatakan Anda salah tentang hal itu. Saya hanya mengatakan bahwa membatalkannya hanya untuk yang satu ini adalah hukuman yang keras. Saya setuju dengan Anda, namun, 4 upvotes tidak menghasilkan 4 downvotes. Saya akan meningkatkan komentar Anda juga, tetapi saya tidak akan menurunkan jawaban karena keterlambatan yang tidak dapat dijelaskan :)
ThunderGr
1
@RubenBartelink dan lainnya: walaupun saya tidak secara khusus menyukai kode ini (saya telah memposting solusi lain dengan pendekatan yang sama), penundaan di sini masuk akal. Masalahnya kemungkinan besar di luar kendali aplikasi; mungkin aplikasi lain memindai FS secara berkala, sehingga mengunci folder untuk periode waktu yang singkat. Penundaan menyelesaikan masalah, membuat laporan bug hitung mundur ke nol. Siapa yang peduli jika kita tidak punya ide tentang akar penyebabnya?
Andrey Tarantsov
1
@RubenBartelink Bahkan, ketika Anda memikirkannya, tidak menggunakan pendekatan penundaan dan coba lagi selama penghapusan direktori NTFS adalah solusi yang tidak bertanggung jawab di sini. Segala jenis traversal file yang sedang berlangsung akan memblokir penghapusan, jadi itu pasti akan gagal cepat atau lambat. Dan Anda tidak dapat mengharapkan semua alat pencarian pihak ketiga, cadangan, antivirus dan manajemen file untuk tetap keluar dari folder Anda.
Andrey Tarantsov
1
@RubenBartelink Ex. Lainnya, misalnya Anda memberi penundaan 100 ms, dan waktu penguncian tertinggi dari semua perangkat lunak pada PC target adalah perangkat lunak AV = 90 ms. Katakan itu juga memiliki perangkat lunak cadangan yang mengunci file selama 70 ms. Sekarang AV mengunci file, aplikasi Anda menunggu 100 ms, yang biasanya baik-baik saja, tetapi kemudian menemukan kunci lain karena perangkat lunak cadangan mulai mengambil file pada tanda 70 ms dari pemindaian AV, sehingga akan membutuhkan 40 ms untuk melepaskan file. Jadi, sementara perangkat lunak AV membutuhkan waktu lebih lama & 100ms Anda biasanya lebih lama dari salah satu dari 2 aplikasi, Anda masih harus memperhitungkan kapan itu dimulai di tengah.
vapcguy
2

Penghapusan direktori rekursif yang tidak menghapus file tentu tidak terduga. Perbaikan saya untuk itu:

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

Saya mengalami kasus di mana ini membantu, tetapi secara umum, Directory.Delete menghapus file di dalam direktori setelah penghapusan rekursif, seperti yang didokumentasikan dalam msdn .

Dari waktu ke waktu saya menemukan perilaku tidak teratur ini juga sebagai pengguna Windows Explorer: Kadang-kadang saya tidak dapat menghapus folder (itu berpikir pesan tidak masuk akal adalah "akses ditolak") tetapi ketika saya menelusuri dan menghapus item yang lebih rendah saya kemudian dapat menghapus bagian atas barang juga. Jadi saya kira kode di atas berkaitan dengan anomali OS - bukan dengan masalah pustaka kelas dasar.

citykid
sumber
1

Direktori atau file di dalamnya terkunci dan tidak dapat dihapus. Temukan pelakunya yang menguncinya dan lihat apakah Anda dapat menghilangkannya.

Vilx-
sumber
T1000 untuk pengguna-dengan-folder-terbuka: "Anda dihentikan!"
vapcguy
1

Tampaknya memiliki jalur atau subfolder yang dipilih di Windows Explorer sudah cukup untuk memblokir satu eksekusi Directory.Delete (path, true), melempar IOException seperti dijelaskan di atas dan sekarat alih-alih mem-boot Windows Explorer ke folder induk dan memproses sebagai diharapkan.

David Alpert
sumber
Ini tampaknya menjadi masalah saya. Segera setelah saya menutup Explorer dan berlari lagi, tidak terkecuali. Bahkan memilih induk orangtua tidak cukup. Saya harus menutup Explorer.
Scott Marlowe
Ya, ini terjadi dan merupakan penyebab. Jadi ada ide bagaimana cara menghadapinya secara terprogram, atau apakah jawabannya selalu untuk memastikan semua 1000 pengguna memiliki folder yang ditutup?
vapcguy
1

Saya punya masalah ini hari ini. Itu terjadi karena saya memiliki windows explorer yang terbuka ke direktori yang mencoba untuk dihapus, menyebabkan panggilan rekursif gagal dan dengan demikian IOException. Pastikan tidak ada pegangan yang terbuka ke direktori.

Juga, MSDN jelas bahwa Anda tidak harus menulis resusi Anda sendiri: http://msdn.microsoft.com/en-us/library/fxeahc5f.aspx

GrokSrc
sumber
1

Saya punya masalah yang sama dengan Windows Workflow Foundation di server build dengan TFS2012. Secara internal, alur kerja disebut Directory.Delete () dengan flag rekursif disetel ke true. Tampaknya terkait dengan jaringan dalam kasus kami.

Kami menghapus folder jatuhkan biner pada jaringan berbagi sebelum menciptakan kembali dan mengisinya kembali dengan binari terbaru. Setiap bangunan lainnya akan gagal. Ketika membuka folder drop setelah pembangunan gagal, folder itu kosong, yang menunjukkan bahwa setiap aspek panggilan Directory.Delete () berhasil kecuali untuk menghapus direktori sebenarnya.

Masalahnya tampaknya disebabkan oleh sifat asinkron komunikasi file jaringan. Build server memberi tahu server file untuk menghapus semua file dan server file melaporkannya, meskipun belum sepenuhnya selesai. Kemudian build server meminta agar direktori dihapus dan server file menolak permintaan itu karena belum selesai menghapus file.

Dua kemungkinan solusi dalam kasus kami:

  • Membangun penghapusan rekursif dalam kode kita sendiri dengan penundaan dan verifikasi antara setiap langkah
  • Coba lagi hingga X kali setelah IOException, berikan penundaan sebelum mencoba lagi

Metode terakhir cepat dan kotor tetapi tampaknya melakukan trik.

Shaun
sumber
1

Ini karena FileChangesNotifications.

Itu terjadi sejak ASP.NET 2.0. Ketika Anda menghapus beberapa folder dalam suatu aplikasi, itu akan dimulai kembali . Anda dapat melihatnya sendiri, menggunakan ASP.NET Health Monitoring .

Tambahkan saja kode ini ke web.config / konfigurasi / system.web Anda:

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


Setelah itu periksa Windows Log -> Application. Apa yang sedang terjadi:

Ketika Anda menghapus folder, jika ada sub-folder, hapus Delete(path, true)sub-folder terlebih dahulu. Cukup untuk FileChangesMonitor tahu tentang penghapusan dan matikan aplikasi Anda. Sementara itu direktori utama Anda belum dihapus. Ini adalah acara dari Log:


masukkan deskripsi gambar di sini


Delete() tidak menyelesaikan pekerjaannya dan karena aplikasi dimatikan, itu menimbulkan pengecualian:

masukkan deskripsi gambar di sini

Ketika Anda tidak memiliki subfolder dalam folder yang Anda hapus, Delete () hanya menghapus semua file dan folder itu, aplikasi juga dimulai ulang, tetapi Anda tidak mendapatkan pengecualian , karena restart aplikasi tidak mengganggu apa pun. Tapi tetap saja, Anda kehilangan semua sesi dalam proses, aplikasi tidak menanggapi permintaan saat memulai ulang, dll.

Apa sekarang?

Ada beberapa solusi dan penyesuaian untuk menonaktifkan perilaku ini, Direktori Junction , Mematikan FCN dengan Registry , Menghentikan FileChangesMonitor menggunakan Reflection (karena tidak ada metode yang terbuka) , tetapi mereka semua tampaknya tidak benar, karena FCN ada untuk alasan. Ini menjaga struktur aplikasi Anda , yang bukan struktur data Anda . Jawaban singkatnya adalah: folder tempat yang ingin Anda hapus di luar aplikasi Anda. FileChangesMonitor tidak akan menerima pemberitahuan dan aplikasi Anda tidak akan dimulai ulang setiap saat. Anda tidak akan mendapatkan pengecualian. Untuk membuatnya terlihat dari web ada dua cara:

  1. Buat pengontrol yang menangani panggilan masuk dan kemudian melayani file kembali dengan membaca dari folder di luar aplikasi (di luar wwwroot).

  2. Jika proyek Anda besar dan kinerjanya paling penting, buat server web kecil dan cepat yang terpisah untuk menyajikan konten statis. Dengan demikian Anda akan pergi ke IIS pekerjaan spesifiknya. Itu bisa di mesin yang sama (luwak untuk Windows) atau mesin lain (nginx untuk Linux). Berita baiknya adalah Anda tidak perlu membayar lisensi microsoft tambahan untuk mengatur server konten statis di linux.

Semoga ini membantu.

Roma
sumber
1

Seperti disebutkan di atas solusi "diterima" gagal pada titik-titik berulang - namun orang masih menandainya (???). Ada solusi yang jauh lebih pendek yang mereplikasi fungsi dengan benar:

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);
}

Saya tahu, tidak menangani kasus perizinan yang disebutkan kemudian, tetapi untuk semua maksud dan tujuan FAR LEBIH BAIK menyediakan fungsi yang diharapkan dari Direktori asli / stok. Hapus () - dan dengan kode yang jauh lebih sedikit juga .

Anda dapat dengan aman melanjutkan pemrosesan karena dir yang lama akan keluar dari jalan ... bahkan jika tidak hilang karena 'sistem file masih mengejar ketinggalan' (atau alasan apa pun yang diberikan MS untuk menyediakan fungsi yang rusak) .

Sebagai manfaat, jika Anda tahu direktori target Anda besar / dalam dan tidak ingin menunggu (atau repot-repot dengan pengecualian) baris terakhir dapat diganti dengan:

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

Anda masih aman untuk terus bekerja.

rampok
sumber
2
Bisakah tugas Anda disederhanakan dengan: string tfilename = Path.Combine (Path.GetDirectoryName (target), Path.GetRandomFileName ());
Pete
1
Saya harus setuju dengan Pete. Kode seperti ditulis tidak akan menambah pemisah. Ia mengambil jalan saya \\server\C$\dirdan berhasil \\server\C$asf.yuw. Akibatnya saya mendapat kesalahan pada Directory.Move()- Source and destination path must have identical roots. Move will not work across volumes. Bekerja dengan baik setelah saya menggunakan kode Pete KECUALI tidak menangani ketika ada file terkunci atau membuka direktori-jadi tidak pernah sampai ke ThreadPoolperintah.
vapcguy
PERHATIAN: Jawaban ini hanya boleh digunakan dengan rekursif = benar. Ketika false, ini akan Memindahkan direktori walaupun tidak kosong. Yang akan menjadi bug; perilaku yang benar dalam kasus itu adalah dengan melemparkan pengecualian, dan meninggalkan direktori seperti semula.
ToolmakerSteve
1

Masalah ini dapat muncul pada Windows ketika ada file dalam direktori (atau dalam subdirektori apa pun) yang panjang lintasannya lebih besar dari 260 simbol.

Dalam kasus seperti itu Anda perlu menghapus \\\\?\C:\mydirbukan C:\mydir. Tentang batas 260 simbol Anda dapat membaca di sini .

HostageBrain
sumber
1

Saya telah memecahkan dengan teknik milenary ini (Anda dapat meninggalkan Thread. Tidur sendiri di tangkapan)

bool deleted = false;
        do
        {
            try
            {
                Directory.Delete(rutaFinal, true);                    
                deleted = true;
            }
            catch (Exception e)
            {
                string mensaje = e.Message;
                if( mensaje == "The directory is not empty.")
                Thread.Sleep(50);
            }
        } while (deleted == false);
Mauricio Rdz
sumber
0

Jika direktori aplikasi Anda (atau aplikasi lain) saat ini adalah yang Anda coba hapus, itu tidak akan menjadi kesalahan pelanggaran akses tetapi direktori tidak kosong. Pastikan itu bukan aplikasi Anda sendiri dengan mengubah direktori saat ini; juga, pastikan direktori tidak terbuka di beberapa program lain (mis. Word, excel, Total Commander, dll.). Sebagian besar program akan melakukan cd ke direktori file terakhir yang dibuka, yang akan menyebabkannya.

konfigurator
sumber
0

dalam hal file jaringan, Directory.DeleteHelper (rekursif: = true) dapat menyebabkan IOException yang disebabkan oleh keterlambatan menghapus file

berkokok
sumber
0

Saya pikir ada file yang dibuka oleh aliran yang tidak Anda sadari bahwa saya memiliki masalah yang sama dan menyelesaikannya dengan menutup semua aliran yang mengarah ke direktori yang ingin saya hapus.

Ahmad Moussa
sumber
0

Kesalahan ini terjadi jika ada file atau direktori yang dianggap sedang digunakan. Itu adalah kesalahan menyesatkan. Periksa untuk melihat apakah Anda memiliki jendela explorer atau jendela baris perintah terbuka ke direktori apa pun di pohon, atau program yang menggunakan file di pohon itu.

allen1
sumber
0

Saya memecahkan satu contoh yang mungkin dari masalah yang dinyatakan ketika metode async dan dikodekan seperti ini:

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

Dengan ini:

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);

Kesimpulan? Ada beberapa aspek asinkron untuk menyingkirkan pegangan yang digunakan untuk memeriksa keberadaan yang belum dapat diajak bicara oleh Microsoft. Seolah-olah metode asinkron di dalam pernyataan if memiliki pernyataan if yang bertindak seperti pernyataan using.

Pat Pattillo
sumber
0

Anda tidak perlu membuat dan metode tambahan untuk pengulangan atau menghapus file di dalam folder ekstra. Ini semua dilakukan secara otomatis dengan menelepon

DirectoryInfo.Delete ();

Detail ada di sini .

Sesuatu seperti ini bekerja dengan sangat baik:

  var directoryInfo = new DirectoryInfo("My directory path");
    // Delete all files from app data directory.

    foreach (var subDirectory in directoryInfo.GetDirectories())
    {
          subDirectory.Delete(true);// true set recursive paramter, when it is true delete sub file and sub folder with files too
    }

lewat benar sebagai variabel untuk menghapus metode, akan menghapus sub file dan sub folder dengan file juga.

nzrytmn
sumber
-2

Tidak ada jawaban di atas yang berfungsi untuk saya. Tampaknya penggunaan aplikasi saya sendiri untukDirectoryInfo pada direktori target menyebabkannya tetap terkunci.

Memaksa pengumpulan sampah muncul untuk menyelesaikan masalah, tetapi tidak segera. Beberapa upaya untuk menghapus jika diperlukan.

Catat Directory.Existskarena dapat menghilang setelah pengecualian. Saya tidak tahu mengapa penghapusan untuk saya tertunda (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.");
Reactgular
sumber
1
-1 Pemrograman secara kebetulan. Apa yang dilakukan objek apa saat GC? Apakah ini saran umum yang baik? (Saya percaya Anda ketika Anda mengatakan Anda memiliki masalah dan bahwa Anda menggunakan kode ini dan bahwa Anda merasa tidak memiliki masalah sekarang tetapi itu bukan intinya)
Ruben Bartelink
@RubenBartelink saya setuju. Ini hack. Kode Voodoo yang melakukan sesuatu ketika tidak jelas apa yang dipecahkan atau bagaimana caranya. Saya akan menyukai solusi yang tepat.
Reactgular
1
Masalah saya adalah apa pun yang ditambahkan di atas dan di atas stackoverflow.com/a/14933880/11635 sangat spekulatif. Jika saya bisa, saya akan memberikan -1 untuk duplikasi dan -1 untuk spekulasi / pemrograman secara kebetulan. Penyiraman GC.Collectadalah a) hanya Saran Buruk dan b) bukan penyebab umum yang cukup umum dari dirs yang dikunci agar pantas dimasukkan di sini. Pilih saja salah satu dari yang lain dan jangan menabur lebih banyak kebingungan di benak pembaca yang tidak bersalah
Ruben Bartelink
3
Gunakan GC.WaitForPendingFinalizers (); setelah GC.Collect (); ini akan berfungsi seperti yang diharapkan.
Heiner
Tidak yakin, belum diuji, tetapi mungkin lebih baik melakukan sesuatu dengan usingpernyataan, lalu: using (DirectoryInfo di = new DirectoryInfo(@"c:\MyDir")) { for (int attempts = 0; attempts < 10; attempts++) { try { if (di.Exists(folder)) { Directory.Delete(folder, true); } return; } catch (IOException e) { Thread.Sleep(1000); } } }
vapcguy
-3

tambahkan true di param kedua.

Directory.Delete(path, true);

Itu akan menghapus semua.

Santiago Medina Chaverra
sumber
1
Directory.Delete (path, true); adalah pertanyaan awal
Pisu