Directory.Delete ile dizin silinemiyor (yol, true)


383

.NET 3.5 kullanarak, bir dizini özyinelemeli kullanarak bir dizini silmeye çalışıyorum:

Directory.Delete(myPath, true);

Anladığım kadarıyla, dosyalar kullanımdaysa veya bir izin sorunu varsa bunun atması gerekir, ancak aksi takdirde dizini ve tüm içeriğini silmesi gerekir.

Ancak, bazen bu olsun:

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

Yöntemin bazen attığına şaşırmadım, ancak özyinelemeli doğru olduğunda bu belirli mesajı almama şaşırdım. ( Dizinin boş olmadığını biliyorum .)

Bunu AccessViolationException yerine görmem için bir neden var mı?


13
AccessViolationException'ı görmezsiniz - bu, disk erişimi için değil, geçersiz işaretçi işlemleri içindir.
Joe White

1
Bu, açık dosya tanıtıcıları veya başka bir şey gibi, dizinin boş olmaması dışında bir tür GÇ sorunu gibi görünüyor. Özyinelemeli silme seçeneğini kullanmayı dener, sonra IOException için bir yakalamada, açık dosya tanıtıcılarını arar ve kapatır, sonra tekrar denerim. Bu konuda bir tartışma var: stackoverflow.com/questions/177146/…
Dan Csharpster

Yanıtlar:


231

Editörün notu: Bu cevap bazı yararlı bilgiler içermekle birlikte, çalışmasıyla ilgili aslında yanlıştır Directory.Delete. Lütfen bu yanıtın yorumlarını ve bu sorunun diğer yanıtlarını okuyun.


Daha önce bu problemle karşılaştım.

Sorunun kökü, bu işlevin dizin yapısı içindeki dosyaları silmemesidir. Yapmanız gereken şey, dizinin kendisini kaldırmadan önce dizin yapısı içindeki tüm dosyaları, sonra tüm dizinleri silen bir işlev oluşturmaktır. Bunun ikinci parametreye aykırı olduğunu biliyorum ama bu çok daha güvenli bir yaklaşım. Ayrıca, büyük olasılıkla silmeden hemen önce dosyalardan READ-ONLY özniteliklerini kaldırmak isteyeceksiniz. Aksi takdirde bu bir istisna doğuracaktır.

Bu kodu projenize yapıştırın.

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

Ayrıca, benim için kişisel olarak makinenin silinmesine izin verilen alanlara bir kısıtlama ekliyorum çünkü birisinin bu işlevi çağırmasını istiyor musunuz C:\WINDOWS (%WinDir%)veya C:\.


117
Bu saçmalık. Directory.Delete (myPath, true), dizin yapısı içindeki tüm dosyaları silen bir aşırı yüklenmedir. Eğer yanlış yapmak istiyorsanız, Ryan S'nin cevabı ile yanlış yapın.
Sig. Tolleranza

35
Directory.Delete (), alt dizinlerindeki dosyaları (yinelemeli = true ile) silmesine rağmen, alt dizinlerden veya dosyalardan biri salt okunursa "IOException: Dizin boş değildir" atar. Yani bu çözüm Directory.Delete () 'den daha iyi çalışır
Anthony Brien

17
İfadende Directory.Delete(path, true)dosyaları silmez yanlıştır. Bkz. MSDN msdn.microsoft.com/tr-tr/library/fxeahc5f.aspx
Konstantin Spirin

20
-1 Birisi lütfen bu yaklaşımın geçerliliğinden şüphe duyduğunu açıkça belirtebilir mi? Eğer Directory.Delete(string,bool)başarısız şey kilitli veya mispermissioned ve böyle bir sorunun tüm çözüm kimse boyutu uyuyor yoktur. İnsanların bu konuyu kendi bağlamlarında ele almaları gerekiyor ve büyük bir kıllı büyümeye devam edeceğiz (problemi yeniden denemek (istismar ve istisna ile)) ve iyi bir sonuç umuyoruz.
Ruben Bartelink

37
Dizininizde silme işleminizin diğer klasörlere kısayolları / sembolik bağlantıları varsa bu yaklaşıma dikkat edin - sonuçta beklediğinizden daha fazlasını
silebilirsiniz

182

Dizini özyinelemeli olarak silmeye çalışıyorsanız ave dizin a\bExplorer'da açıksa bsilinir, ancak agittiğinizde ve baktığınızda boş olsa bile 'dizin boş değil' hatasını alırsınız . Herhangi bir uygulamanın (Explorer dahil) geçerli dizini , dizin için bir tanıtıcı tutar . Aradığınızda Directory.Delete(true), aşağıdan yukarıya siler:, bsonra a. Eğer bExplorer'da açıktır Explorer silinmesini algılar byukarı değişim dizini cd ..ve açık kolları temizlemek. Dosya sistemi zaman uyumsuz olarak çalıştığından, Directory.DeleteExplorer ile çakışmalar nedeniyle işlem başarısız olur.

Eksik çözüm

Başlangıçta Explorer'ın dizin tanıtıcısını serbest bırakması için izin vermek için geçerli iş parçacığını kesme fikriyle aşağıdaki çözümü gönderdim.

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

Ancak bu yalnızca açık dizin, sildiğiniz dizinin hemen alt öğesi ise işe yarar . Eğer a\b\c\dExplorer'da açıktır ve bu konuda kullanmak a, bu teknik silindikten sonra başarısız olur dve c.

Biraz daha iyi bir çözüm

Bu yöntem, alt düzey dizinlerden biri Gezgin'de açık olsa bile derin bir dizin yapısının silinmesini işleyecektir.

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

Tek başına tekrarlama çalışmalarına rağmen, yine de UnauthorizedAccessExceptionyol boyunca meydana gelebilecek olanı ele almalıyız . İlk silme girişiminin ikinci, başarılı olana yol açıp açmadığı veya sadece dosya sisteminin yakalanmasına izin veren bir istisna atma / yakalama tarafından getirilen zamanlama gecikmesi olup olmadığı açık değildir.

Bloğun Thread.Sleep(0)başına a ekleyerek tipik koşullar altında atılan ve yakalanan istisnaların sayısını azaltabilirsiniz try. Ayrıca, ağır sistem yükü altında, her iki Directory.Deletedenemeden de geçip başarısız olma riski vardır . Bu çözümü daha sağlam yinelemeli silme için bir başlangıç ​​noktası olarak düşünün.

Genel cevap

Bu çözüm yalnızca Windows Gezgini ile etkileşimin özelliklerini ele alır. Kaya gibi sağlam bir silme işlemi istiyorsanız, akılda tutulması gereken bir şey, herhangi bir şeyin (virüs tarayıcı, ne olursa olsun), silmeye çalıştığınız şeyin herhangi bir zamanda açık bir tutamağı olabileceğidir. Bu yüzden daha sonra tekrar denemek zorundasınız. Ne kadar sonra ve kaç kez denediğiniz, nesnenin silinmesinin ne kadar önemli olduğuna bağlıdır. As MSDN gösterir ,

Sağlam dosya yineleme kodu, dosya sisteminin birçok karmaşıklığını dikkate almalıdır.

Yalnızca NTFS başvuru belgelerine bir bağlantıyla sağlanan bu masum ifade, saçlarınızı dik tutmalıdır.

( Düzenleme : Çok. Bu cevap başlangıçta sadece tamamlanmamış ilk çözüme sahipti.)


11
Dizin çağrılıyor gibi görünüyor. Yol veya yol altındaki klasörlerden / dosyalardan biri açıkken veya Windows Gezgini'nde seçildiğinde bir IOException kurar. Windows Gezgini'nin kapatılması ve mevcut kodumu yukarıda önerilen try / catch olmadan yeniden çalıştırması iyi sonuç verdi.
David Alpert

1
Nasıl ve neden çalıştığını anlayamıyorum ama dosya özniteliklerini ayarlarken ve kendi özyinelemeli işlevimi yazarken benim için çalıştı.
Stilgar

1
@CarlosLiu Çünkü "Explorer dizin tutamacını serbest bırakma şansı veriyor"
Dmitry Gonchar

4
Olan şey, sistemin Explorer'dan "dizin tanıtıcısını serbest bırakmasını" istemesini ve ardından dizini silmeyi denemesidir. Dizin tanıtıcısı zamanında silinmediyse, bir özel durum oluşur ve catchblok yürütülür (bu arada, bunu yapmamasını söyleyen bir komut gönderilmediğinden, Explorer dizini hala serbest bırakır). Blok, sisteme zaten biraz daha zaman vermiş Thread.Sleep(0)olduğu için çağrı gerekebilir veya gerekmeyebilir catch, ancak düşük bir maliyet için biraz ekstra güvenlik sağlar. Bundan sonra Delete, dizin zaten serbest bırakılmış olarak çağrılır.
Zachary Kniebel

1
@PandaWood aslında sadece bu Uyku (100) benim için çalıştı. Uyku (0) işe yaramadı. Neler olduğu ve bunun nasıl doğru bir şekilde çözüleceği hakkında hiçbir fikrim yok. Yani, sunucu yüküne bağlıysa ve gelecekte 300 veya 400 olmalı? Bunu nasıl bilebilirim? Başka bir uygun yol olmalı ...
Roman

43

Daha ileri gitmeden önce, kontrolünüz altında olan aşağıdaki nedenleri kontrol edin:

  • Klasör, işleminizin geçerli bir dizini olarak mı ayarlanmış? Evetse, önce başka bir şeye değiştirin.
  • Bu klasörden bir dosya açtınız mı (veya bir DLL yüklediniz)? (ve kapatmayı / boşaltmayı unuttum)

Aksi takdirde, kontrolünüz dışındaki aşağıdaki meşru nedenleri kontrol edin:

  • Bu klasörde salt okunur olarak işaretlenmiş dosyalar var.
  • Bu dosyaların bazıları için silme izniniz yok.
  • Dosya veya alt klasör Explorer'da veya başka bir uygulamada açık.

Yukarıdakilerden herhangi biri sorunsa, silme kodunuzu geliştirmeye çalışmadan önce bunun neden olduğunu anlamalısınız. Uygulamanız salt okunur veya erişilemeyen dosyaları mı siliyor olmalı ? Onları bu şekilde kim işaretledi ve neden?

Yukarıdaki nedenleri dışladıktan sonra, hala sahte başarısızlık olasılığı vardır. Herhangi biri silinmekte olan dosya veya klasörlerin herhangi bir tanıtıcısına sahipse silme başarısız olur ve birisinin klasörü numaralandırmasının veya dosyalarını okumasının birçok nedeni olabilir:

  • arama dizinleyicileri
  • Anti-virüs
  • yedekleme yazılımı

Sahte başarısızlıklarla başa çıkmak için genel yaklaşım, girişimler arasında duraklayarak birden fazla kez denemektir. Açıkçası sonsuza kadar denemeye devam etmek istemiyorsunuz, bu nedenle belirli sayıda denemeden sonra vazgeçmeli ve bir istisna atamalı veya hatayı yok saymalısınız. Bunun gibi:

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
}

Benim düşünceme göre, böyle bir yardımcı tüm silmeler için kullanılmalıdır çünkü sahte hatalar her zaman mümkündür. Ancak, bu kodu sadece körü körüne kopyalamakla kalmaz, KULLANIM DURUMUNUZA KABUL ETMELİSİNİZ.

Benim app tarafından oluşturulan,% LocalAppData% altında bulunan bir iç veri klasörü için sahte hataları vardı, bu yüzden benim analiz şöyle gider:

  1. Klasör yalnızca uygulamam tarafından denetlenir ve kullanıcının bu klasörün içinde işleri salt okunur veya erişilemez olarak işaretlemek için geçerli bir nedeni yoktur, bu nedenle bu durumu ele almaya çalışmıyorum.

  2. İçeride kullanıcı tarafından yaratılan değerli bir şey yoktur, bu nedenle yanlışlıkla bir şeyi zorla silme riski yoktur.

  3. Dahili bir veri klasörü olarak, explorer'da açık olmasını beklemiyorum, en azından özel olarak davayı ele alma ihtiyacını hissetmiyorum (yani destekle bu vakayı ele alıyorum).

  4. Tüm denemeler başarısız olursa, hatayı yok saymayı seçerim. En kötü durumda, uygulama bazı yeni kaynakları açamıyor, çöküyor ve kullanıcıdan sık sık olmadığı sürece benim için kabul edilebilir destek ile iletişim kurmasını istiyor. Veya uygulama çökmezse, yine benim için kabul edilebilir bazı eski veriler bırakacaktır.

  5. Yeniden denemeleri 500ms (50 * 10) ile sınırlamayı seçiyorum. Bu pratikte çalışan keyfi bir eşiktir; Eşiğin yeterince kısa olmasını istedim, böylece kullanıcılar uygulamayı yanıtlamayı bıraktığını düşünerek uygulamayı öldürmeyecekti. Öte yandan, suçlunun klasörümü işlemeyi bitirmesi yarım saniye sürüyor. Bazen Sleep(0)kabul edilebilir bile olan diğer SO cevaplarına bakıldığında , çok az kullanıcı tek bir denemeden daha fazlasını deneyimleyecektir.

  6. Her 50 ms'de bir başka keyfi sayı olan yeniden deniyorum. Bir dosyayı silmeye çalıştığımda işleniyorsa (dizine eklenmiş, işaretlenmişse), işlemimde işlemin tamamlanmasını beklemek için 50 msn doğru zaman olduğunu hissediyorum. Ayrıca, 50ms fark edilir bir yavaşlamaya neden olmayacak kadar küçüktür; yine, Sleep(0)birçok durumda yeterli gibi görünüyor, bu yüzden çok fazla geciktirmek istemiyoruz.

  7. Kod, tüm G / Ç istisnalarını dener. Normalde% LocalAppData% öğesine erişen herhangi bir istisna beklemiyorum, bu yüzden basitliği seçtim ve meşru bir istisna olması durumunda 500ms gecikme riskini kabul ettim. Ayrıca, yeniden denemek istediğim istisnayı tespit etmek için bir yol bulmak istemedim.


7
PPS Birkaç ay sonra, bu (biraz delice) kod parçasının sorunu tamamen çözdüğünü bildirmekten mutluluk duyuyorum. Bu sorunla ilgili destek istekleri sıfıra iner (haftada yaklaşık 1-2).
Andrey Tarantsov

1
+0 Bu daha sağlam ve daha az olsa da 'burada; benim için mükemmel çözüm stackoverflow.com/a/7518831/11635 , benim için de aynısı geçerlidir - tesadüfle programlama - dikkatli davranın. Kodunuzda yer alan kullanışlı bir nokta, yeniden deneme yapacaksanız, Dizinin son denemeden bu yana 'Gitti' olup olmadığı belirsizliği ile bir yarışta olduğunuzu düşünmenizdir [ve bir Directory.Existsnöbetçi bunu çözmez.]
Ruben Bartelink

1
seviyorum ... ne yaptığımı bilmiyorum, bu benim için her zaman bir acı noktası ... ama bunun nedeni, dizinde explorer'da açık olduğum için değil ... internette bu konuda çok fazla artış yok -veya daha az hata ... en azından ben ve Andrey onunla başa çıkmak için bir yol var :)
TCC

2
@RubenBartelink Tamam, bu yüzden bunu kabul edebileceğimizi düşünüyorum: SO cevabı birçok acemi için bir kötülük olacak gibi belirli bir uygulama için çalışan bir kod parçası (ve her durumda uygun olmadı asla) / veya cahil geliştiriciler. Özelleştirme için bir başlangıç ​​noktası olarak verdim, ama evet, bazı insanlar onu olduğu gibi kullanacak ve bu kötü bir şey.
Andrey Tarantsov

2
@nopara Karşılaştırmaya ihtiyacınız yok; döngüden çıkarsak başarısız olduk. Ve evet, birçok durumda istisna atmak, ardından muhtemelen kullanıcı tarafından görülebilir bir mesajla yığına uygun hata işleme kodu eklemek isteyeceksiniz.
Andrey Tarantsov

18

Modern Async Cevabı

Kabul edilen cevap sadece yanlıştır, bazı insanlar için işe yarayabilir, çünkü dosyaları diskten almak için geçen süre dosyaları kilitleyen her şeyi boşaltır. Gerçek şu ki, dosyalar başka bir işlem / akış / eylem tarafından kilitlendiğinden oluşur. Diğer yanıtlar Thread.Sleep, bir süre sonra dizini silmeyi yeniden denemek için (Yuck) komutunu kullanır . Bu sorunun daha modern bir cevapla tekrar gözden geçirilmesi gerekiyor.

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

Birim Testleri

Bu sınamalar, kilitli bir dosyanın Directory.Deletenasıl başarısız olmasına ve TryDeleteDirectoryyukarıdaki yöntemin sorunu nasıl çözdüğüne bir örnek gösterir .

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

"Modern" ile ne demek istediğinizi genişletebilir misiniz? Yaklaşımınızın faydaları nelerdir? Sizce diğerleri neden yanlış?
TinyRacoon

1
Diğerleri yanlış değil. Onlar sadece Thread.Sleepbugün kaçınmak gibi eski API'ları kullanın ve bunun yerine async/ kullanın. Bu anlaşılabilir bir durum, bu çok eski bir soru. awaitTask.Delay
Muhammad Rehan Saeed

Bu yaklaşım, BC36943 'Await' cannot be used inside a 'Catch' statement, a 'Finally' statement, or a 'SyncLock' statement.
VB.Net'te

@amonroejj Daha eski bir sürüm kullanıyor olmalısınız. Bu düzeltildi.
Muhammad Rehan Saeed

if (!Directory.Exists(directoryPath)) { return true; } await Task.Delay(millisecondsDelay); Dizin gerçekten bitene kadar beklemek için dönüş yerine küçük bir gelişme
fuchs777

16

Belirtilmesi gereken önemli bir şey (bir yorum olarak ekledim ama izin verilmiyor) aşırı yükün davranışının .NET 3.5'ten .NET 4.0'a değişmesidir.

Directory.Delete(myPath, true);

.NET 4.0'dan başlayarak klasördeki dosyaları siler ancak 3.5'te DEĞİLDİR. Bu, MSDN belgelerinde de görülebilir.

.NET 4.0

Belirtilen dizini ve belirtilmişse dizindeki tüm alt dizinleri ve dosyaları siler .

.NET 3.5

Boş bir dizini ve belirtilmişse dizindeki tüm alt dizinleri ve dosyaları siler .


3
Bence bu sadece bir belge değişikliği ... sadece "boş bir dizin" silerse, 2 ° parametresi ile dizindeki dosyaları da silmek ne anlama gelir?
Boşsa

Korkarım yanlış olduğunu varsayıyorsun. Bu kodu her iki çerçeve sürümü ile test ettikten sonra gönderdim. 3.5'te boş olmayan bir klasörü silmek bir istisna atar.
jettatore

15

Aynı problemi Delphi altında yaşadım. Ve sonuçta kendi uygulamam silmek istediğim dizini kilitliyordu. Bir şekilde dizin yazarken kilitlendi (bazı geçici dosyalar).

Yakalama 22, silmeden önce ebeveynine basit bir değişiklik dizini yaptım.


6
+1 Şimdi Directory.Delete için msdn'nin bahsettiği bir şey var!
Ruben Bartelink

3
bu konuda çalışan tam kaynak kodu örneği ile herhangi bir son çözüm?
Kiquenet

11

Hiç kimsenin, her birinin salt okunur özniteliğini değiştirmeye gerek kalmadan salt okunur dosyaları içeren dizinleri silebilen bu basit özyinelemeli olmayan yöntemi düşünmediğine şaşırdım.

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

(İnternette bulunan bir cmd penceresini bir an için açmamak için biraz değiştirin)


Bizimle paylaşmak güzel ama net üzerinden aramak için bize sormadan, cmd penceresini ateş önlemek için gerekli biraz değişiklik eklemek için nazik misiniz?
Kasım'da ThunderGr

Bu işe yaramıyor. Dosyayı bir komut isteminden veya Explorer'dan silebildiğim durumda, rmdir'i çağırmak için bu kodu kullanmak "Dizin boş değil" anlamına gelen çıkış kodunu 145 verir. Dizini boş bırakıyor ama yine de yerinde duruyor, tıpkı Directory.Delete ("", true) gibi
Kevin Coulombe

@Kevin Coulombe, Humm ... / s / q anahtarlarını kullandığınızdan emin misiniz?
Piyush Soni

1
@KevinCoulombe: Evet, bu COM bileşenleri olmalı. Düz eski C # denediğimde, çalışır ve içindeki dosyalar ile birlikte dizini siler (salt okunur veya salt okunur olanlar).
Piyush Soni

5
Eğer çerçevede olması gerekenler için harici bileşenlere güvenmeye başlarsanız, o zaman artık taşınabilir değil (veya daha zor) bir "idealden daha az" bir fikir coz. Exe orada değilse ne olur? Veya / seçeneği değişti mi? Jeremy Edwards'ın çözümü işe
yarıyorsa,

11

Hatayı çalıştırarak yeniden oluşturabilirsiniz:

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' dizinini silmeye çalışırken, "Dizin boş değil" IOException özel durumunu atar. 'C' dizinini sildiğimiz için bu çok aptalca.

Anladığım kadarıyla, açıklama 'c' dizininin silindi olarak damgalanmasıdır. Ancak silme işlemi henüz sistemde gerçekleştirilmemiştir. Sistem işi yanıtlıyor, aslında işlemeye devam ediyor. Sistem muhtemelen dosya gezgininin silinmesi için üst dizine odaklanmasını bekler.

Sil işlevinin kaynak koduna bakarsanız ( http://referencesource.microsoft.com/#mscorlib/system/io/directory.cs ) yerel Win32Native.RemoveDirectory işlevini kullandığını görürsünüz. Bu beklemeyin davranışı burada belirtilmiştir:

RemoveDirectory işlevi, kapatıldığında silinmek üzere bir dizini işaretler. Bu nedenle, dizin son tutamacı kapatılana kadar dizin kaldırılmaz.

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

Uyku ve yeniden deneme çözümdür. Ryascl'in çözümü.


8

Explorer kabuğunda yapabilmenize rağmen Kullanıcı Profili dizinlerini (C: \ Documents and Settings içinde) silerek garip bir izin sorunu yaşadım.

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

Bir dizinde bir "dosya" işleminin ne yaptığını anlamıyorum, ama bunun işe yaradığını biliyorum ve bu benim için yeterli!


2
Hala umut, dizinde çok sayıda dosya olduğunda ve Explorer bu dosyaları içeren klasörü açıyor.
görür

3

Bu cevap şunlara dayanmaktadır: https://stackoverflow.com/a/1703799/184528 . Benim kod ile fark, biz sadece birçok dizinleri ve dosyaları silmek gerektiğinde Directory.Delete bir çağrı ilk denemede başarısız olur (bir dizine bakarak windows explorer nedeniyle olabilir).

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

Öyleyse, bir klasör varsa nasıl silinir UnauthorizedAccessException? Yine atıyor. Ve yeniden. Ve tekrar ... Çünkü her seferinde catchve fonksiyonunu tekrar arayacak. A Thread.Sleep(0);izinlerinizi değiştirmez. Sadece hatayı günlüğe kaydetmeli ve bu noktada incelikle başarısız olmalıdır. Ve bu döngü (alt-) dizini açık olduğu sürece devam eder - programlı olarak kapatmaz. Bu şeyler açık bırakıldığı sürece bunu yapmasına izin vermeye hazır mıyız? Daha iyi bir yol var mı?
vapcguy

Varsa, UnauthorizedAccessExceptionher dosyayı manuel olarak silmeye çalışır. Böylece dizin yapısına geçerek ilerleme kaydetmeye devam ediyor. Evet, potansiyel olarak her dosya ve dizin aynı istisnayı atar, ancak bu sadece kaşif bir tutamacı tuttuğu için de oluşabilir (bkz. Stackoverflow.com/a/1703799/184528 ) "tryAgain" i "secondTry" olarak değiştireceğim daha açık hale getirmek için.
cdiggins

Daha özlü bir şekilde cevap vermek için "true" değerini geçer ve farklı bir kod yolu yürütür.
cdiggins

Doğru, düzenlemenizi gördüm, ama benim açımdan dosyaların silinmesi değil, dizinin silinmesi. Ben esasen Process.Kill()bir dosya tarafından kilitlenebilir herhangi bir işlem üzerinde yapabileceği bazı kod yazdı ve dosyaları silin. Karşılaştığım sorun, bu dosyalardan birinin hala açık olduğu bir dizini silerken (bkz. Stackoverflow.com/questions/41841590/… ). Yani bu döngüden geri dönersek, başka ne yaparsa yapsın Directory.Delete(), o klasörde tekrar yaparsa, bu tanıtıcı serbest bırakılamazsa yine de başarısız olur.
vapcguy

Aynı şey, UnauthorizedAccessExceptiondosyaları silmeden beri de gerçekleşir (buna bile izin verildiğini varsayarak, bu koda ulaşmak için başarısız oldu Directory.Delete()) sihirli bir şekilde dizini silme izni vermez.
vapcguy

3

Yukarıdaki çözümlerin hiçbiri benim için iyi sonuç vermedi. @Ryascl çözümünün düzenlenmiş bir sürümünü aşağıdaki gibi kullanarak sonuçlandırdım:

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

2

Başka bir iş parçacığının veya işlemin dizine dosya eklediği bir yarış durumunuz olabilir mi:

Sıra şu şekildedir:

Silme işlemi A:

  1. Dizini boşaltın
  2. (Şimdi boş) dizini silin.

Birisi 1 ve 2 arasında bir dosya eklerse, belki 2 listelenen istisnayı atabilir?


2

Bu sorunu ve dizini silmeyle ilgili diğer istisnaları çözmek için birkaç saat geçirdim. Bu benim çözümüm

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

Bu kod, benim uygulama için önemli olmayan küçük bir gecikme vardır. Ancak dikkatli olun, silmek istediğiniz dizinin içinde çok sayıda alt dizin varsa, gecikme sizin için bir sorun olabilir.


8
-1 Gecikme nedir? Tesadüfle programlama yok lütfen!
Ruben Bartelink

1
@Ruben Bu konuda yanlış olduğunu söylemedim. Ben sadece bunun için indirgemek sert bir ceza olduğunu söyledim. Size katılıyorum, ancak 4 upvotes 4 downvotes ile sonuçlanmamıştı. Ben de yorumunuzu yükseltmek istiyorum, ama açıklanamayan bir gecikme nedeniyle cevabı küçümsemek olmaz :)
ThunderGr

1
@RubenBartelink ve diğerleri: özellikle bu kodu sevmiyorum (benzer bir yaklaşımla başka bir çözüm yayınladım), burada gecikme makul. Sorun büyük olasılıkla uygulamanın kontrolü dışındadır; belki başka bir uygulama FS'yi periyodik olarak yeniden tarar ve böylece klasörü kısa süreler boyunca kilitler. Gecikme sorunu çözerek hata raporunu sıfıra indirir. Kök sebeple ilgili hiçbir fikrimiz yoksa kimin umurunda?
Andrey Tarantsov

1
Bunu düşünmek zaman @RubenBartelink In gerçeği, değil NTFS dizini silme işlemi sırasında bir gecikme-ve-yeniden deneme yaklaşımı kullanarak burada sorumsuz bir çözümdür. Devam eden her türlü dosya geçişi, silme işlemini engeller, bu nedenle er ya da geç başarısız olur. Ayrıca tüm üçüncü taraf arama, yedekleme, antivirüs ve dosya yönetimi araçlarının klasörünüzün dışında kalmasını bekleyemezsiniz.
Andrey Tarantsov

1
@RubenBartelink Başka bir örnek, 100 ms gecikme verdiğinizi ve hedef bilgisayardaki herhangi bir yazılımın en yüksek kilitlenme süresinin AV yazılımı = 90 ms olduğunu söylüyor. Ayrıca 70ms için dosyaları kilitleyen bir yedekleme yazılımı olduğunu varsayalım. Şimdi AV bir dosyayı kilitliyor, uygulamanız normalde iyi olan 100 ms'yi bekliyor, ancak daha sonra başka bir kilitle karşılaşıyor, çünkü yedekleme yazılımı AV taramasının 70 ms'lik işaretinde dosyayı tutmaya başlıyor ve bu nedenle dosyayı serbest bırakmak için 40 ms daha alacak. Bu nedenle AV yazılımı daha uzun sürüyor ve 100 msniz normalde 2 uygulamadan birinden daha uzun olsa da, ortada ne zaman başladığını hesaba katmanız gerekir.
vapcguy

2

Dosyaları silmeyen özyinelemeli dizin silme işlemi kesinlikle beklenmedik bir durumdur. Bunun için düzeltmem:

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

Bu yardımcı oldu, ancak genellikle, Directory.Delete msdn belgelendiği gibi özyinelemeli silme üzerine dizinler içindeki dosyaları siler durumları yaşadım .

Zaman zaman bu düzensiz davranışla Windows Gezgini'nin bir kullanıcısı olarak da karşılaşıyorum: Bazen bir klasörü silemiyorum (saçma mesajın "erişim reddedildi" olduğunu düşünüyorum), ancak daha alt öğeleri ayrıntılı olarak sildiğimde silebilirim öğeler de. Bu yüzden yukarıdaki kod bir OS anomalisi ile ilgilenir - bir temel sınıf kütüphane sorunu ile değil sanırım.


1

İçindeki dizin veya bir dosya kilitli ve silinemiyor. Kilitleyen suçluyu bulun ve ortadan kaldırabileceğinizi görün.


T1000 kullanıcı-klasör-açık ile: "Sonlandırıldı!"
17'de vapcguy

1

Windows Gezgini'nde yolun veya alt klasörünün seçili olması, Directory'nin tek bir yürütülmesini engellemek için yeterlidir. Silin (yol, true), yukarıda açıklandığı gibi bir IOException atar ve Windows Gezgini'ni bir üst klasöre önyüklemek yerine ölür ve beklenen.


Bu benim sorunum gibi görünüyor. En kısa sürede Explorer'ı kapatıp tekrar koştuğumda, bir istisna yok. Ebeveynin ebeveynini seçmek bile yeterli değildi. Aslında Explorer'ı kapatmak zorunda kaldım.
Scott Marlowe

Evet, bu olur ve bir nedendir. Peki programlı olarak onunla nasıl başa çıkılacağı hakkında herhangi bir fikir, ya da cevap her zaman 1000 kullanıcının bu klasörün kapalı olduğundan emin olmak mı?
vapcguy

1

Bugün bu problemim vardı. Silinmeye çalışan dizine açık Windows Gezgini vardı, özyinelemeli çağrı başarısız ve böylece IOException neden oldu. Dizine açık tanıtıcı olmadığından emin olun.

Ayrıca, MSDN kendi rencilinizi yazmak zorunda olmadığınız açıktır: http://msdn.microsoft.com/en-us/library/fxeahc5f.aspx


1

TFS2012 ile bir yapı sunucusunda Windows Workflow Foundation ile aynı sorunu yaşadım. Dahili olarak, özyinelemeli bayrak true olarak ayarlanmış şekilde Directory.Delete () adlı iş akışı. Bizim durumumuzda ağ ile ilgili gibi görünüyor.

En son ikili dosyalarla yeniden oluşturmadan ve yeniden doldurmadan önce bir ağ paylaşımındaki bir ikili bırakma klasörünü siliyorduk. Diğer her yapı başarısız olur. Başarısız bir derlemeden sonra bırak klasörü açılırken, klasör boştu; bu, Directory.Delete () çağrısının gerçek dizini silmek dışında her yönünün başarılı olduğunu gösterir.

Sorun ağ dosyası iletişiminin eşzamansız doğasından kaynaklanıyor gibi görünüyor. Yapı sunucusu, dosya sunucusuna tüm dosyaları silmesini söyledi ve dosya sunucusu, tamamlanmamış olmasına rağmen, sahip olduğunu bildirdi. Daha sonra derleme sunucusu dizinin silinmesini istedi ve dosya sunucusu dosyaları silmeyi tamamen bitirmediği için isteği reddetti.

Bizim durumumuzda iki olası çözüm:

  • Her adım arasındaki gecikmeler ve doğrulamalar ile kendi kodumuzda yinelenen silme işlemini oluşturun
  • Bir IOException istisnasından sonra en fazla X kez yeniden deneyin, tekrar denemeden önce gecikme

İkinci yöntem hızlı ve kirli ama hile yapıyor gibi görünüyor.


1

Bunun nedeni FileChangesNotifications.

ASP.NET 2.0'dan beri olur. Bir uygulama içindeki bazı klasörleri sildiğinizde, klasör yeniden başlatılır . ASP.NET Sağlık İzleme'yi kullanarak kendiniz görebilirsiniz .

Bu kodu web.config / configuration / system.web dosyasına eklemeniz yeterlidir:

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


Bundan sonra kontrol edin Windows Log -> Application. Ne oluyor:

Klasörü sildiğinizde, herhangi bir alt klasör varsa, Delete(path, true)önce alt klasörü siler. FileChangesMonitor uygulamasının kaldırma hakkında bilgi sahibi olması ve uygulamanızı kapatması yeterlidir. Bu arada ana dizininiz henüz silinmedi. Bu, Log'daki olay:


resim açıklamasını buraya girin


Delete() işini bitirmedi ve uygulama kapatıldığı için bir istisna ortaya koyuyor:

resim açıklamasını buraya girin

Ne zaman herhangi bir alt klasör yok sildiğiniz bir klasörde, sadece tüm dosya ve bu klasör, uygulama çok yeniden oluyor siler () Sil, ancak herhangi bir özel durumları alamadım uygulama yeniden başlatma kesme şey yapmıyor değil çünkü. Ancak yine de, tüm işlem içi oturumları kaybedersiniz, uygulama yeniden başlatıldığında isteklere yanıt vermez, vb.

Şimdi ne var?

Bu davranışı devre dışı bırakmak için bazı geçici çözümler ve ince ayarlar var , Dizin Bağlantısı , FCN'yi Kayıt Defteri ile Kapatma , FileChangesMonitor'ü Yansıma kullanarak durdurma (çünkü açıkta kalan bir yöntem olmadığı için) , ancak hepsi doğru görünmüyor, çünkü FCN bir sebep. Ne de olsa bakıyor uygulamanızın yapısı değil, verilerin yapısı . Kısa yanıt: silmek istediğiniz klasörleri uygulamanızın dışına yerleştirin. FileChangesMonitor bildirim almaz ve uygulamanız her seferinde yeniden başlatılmaz. Hiçbir istisna alamayacaksınız. Web'den görünür hale getirmenin iki yolu vardır:

  1. Bir uygulamanın dışındaki klasörden (wwwroot dışında) okuyarak gelen aramaları işleyen ve ardından dosyaları geri sunan bir denetleyici yapın.

  2. Projeniz büyükse ve performans çok önemliyse, statik içerik sunmak için ayrı küçük ve hızlı bir web sunucusu kurun. Böylece IIS'ye özel işini bırakacaksınız. Aynı makinede (Windows için mongoose) veya başka bir makinede (Linux için nginx) olabilir. İyi haber şu ki, linux üzerinde statik içerik sunucusu kurmak için ekstra microsoft lisansı ödemek zorunda değilsiniz.

Bu yardımcı olur umarım.


1

Yukarıda belirtildiği gibi "kabul edilen" çözüm, tamir noktalarında başarısız - yine de insanlar hala işaretliyor (???). İşlevi düzgün bir şekilde kopyalayan çok daha kısa bir çözüm var:

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

Biliyorum, daha sonra belirtilen izinleri ele almaz, ancak tüm niyet ve amaçlar için FAR DAHA İYİ orijinal / hisse senedi Directory.Delete () - ve çok daha az kod ile beklenen işlevselliğini sağlar .

Güvenli bir şekilde işlemeye devam edebilirsiniz, çünkü eski dizin yoldan çıkacaktır ... 'dosya sistemi hala yakalanıyor' (veya MS'nin kırık bir işlev sağlamak için verdiği mazeret ne olursa olsun) gitmiş olmasa bile .

Bir avantaj olarak, hedef dizininizin büyük / derin olduğunu ve beklemek istemediğinizi (veya istisnalarla uğraşmak istemediğinizi) biliyorsanız, son satırın yerini alabilir:

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

Hala çalışmaya devam edersiniz.


2
Atamanız şu şekilde basitleştirilebilir: string tfilename = Path.Combine (Path.GetDirectoryName (hedef), Path.GetRandomFileName ());
Pete

1
Pete ile hemfikirim. Yazıldığı gibi kod ayırıcıyı eklemez. Yolumu aldı \\server\C$\dirve başardı \\server\C$asf.yuw. Sonuç olarak ben bir hata var Directory.Move()- Source and destination path must have identical roots. Move will not work across volumes. Ben kilitli dosyalar veya açık dizinler olduğunda ne de kolları dışında Pete kodunu kullandıktan sonra iyi çalıştı-bu yüzden asla ThreadPoolkomut alır .
vapcguy

DİKKAT: Bu yanıt yalnızca özyinelemeli = true ile kullanılmalıdır. Değer yanlış olduğunda, dizini boş olmasa bile taşır. Hangi bir hata olurdu; bu durumda doğru davranış, bir istisna atmak ve dizini olduğu gibi bırakmaktır.
ToolmakerSteve

1

Bu sorun, bir dizinde (veya herhangi bir alt dizinde) yol uzunluğu 260 sembolden büyük dosyalar olduğunda Windows'ta görünebilir.

Bu gibi durumlarda \\\\?\C:\mydirbunun yerine silmeniz gerekir C:\mydir. 260 Hakkında sembolleri okuyabilir sınırlamak burada .


1

Bu binyıl tekniği ile çözdüm (iş parçacığını bırakabilirsiniz.

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

0

Uygulamanızın (veya başka bir uygulamanın) geçerli dizini, silmeye çalıştığınız dizinse, erişim ihlali hatası olmaz, ancak bir dizin boş değildir. Geçerli dizini değiştirerek kendi uygulamanızın olmadığından emin olun; Ayrıca, dizinin başka bir programda açık olmadığından emin olun (örn. Word, excel, Total Commander, vb.). Çoğu program, açılmış olan son dosyanın dizinine cd yapar ve bu da buna neden olur.


0

ağ dosyalarında Directory.DeleteHelper (recursive: = true), dosya silinmesinin gecikmesinden kaynaklanan IOException özelliğine neden olabilir


0

Ben aynı sorun vardı ve silmek istediğim dizini işaret nerede tüm akışları kapatarak çözdüğünü farkında değilsiniz bazı akış tarafından açık bir dosya olduğunu düşünüyorum.


0

Herhangi bir dosya veya dizin kullanımda kabul edilirse bu hata oluşur. Bu yanıltıcı bir hatadır. Ağaçtaki herhangi bir dizine veya o ağaçtaki bir dosyayı kullanan bir programa açık olan herhangi bir explorer pencereniz veya komut satırı pencereniz olup olmadığını kontrol edin.


0

Yöntemler zaman uyumsuz ve bu şekilde kodlandığında belirtilen sorunun olası bir örneğini çözdüm:

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

Bununla:

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

Sonuç? Microsoft'un konuşamadığı varlığı kontrol etmek için kullanılan tanıtıcıdan kurtulmanın bazı asenkron özellikleri vardır. Bir if ifadesinin içindeki asenkron yöntemde, using ifadesi gibi davranan if ifadesi vardır.


0

Özyinelemeye veya klasör ekstra içindeki dosyaları silmeye gerek yoktur. Tüm bunlar arayarak otomatik olarak yapılır

DirectoryInfo.Delete ();

Detaylar burada .

Böyle bir şey oldukça iyi çalışıyor:

  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
    }

silme yöntemine değişken olarak true iletilirse, alt dosyalar ve alt klasörler de dosyalar ile silinir.


-2

Yukarıdaki cevapların hiçbiri benim için işe yaramadı. Görünüşe göre kendi uygulamamın kullanımıDirectoryInfo hedef dizinde kilitli kalmasına neden olduğu anlaşılıyor.

Zorla çöp toplama sorunu çözdü, ancak hemen değil gibi görünüyordu. Gerektiğinde birkaç silme denemesi.

Not Directory.Existsbir istisna sonra kaybolur gibi. Benim için silme işleminin neden ertelendiğini bilmiyorum (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.");

1
-1 Tesadüfle programlama. GC yapıldığında ne nesne yapar? Bu herhangi bir şekilde iyi bir genel tavsiye midir? (Bir sorun yaşadığınızı ve bu kodu kullandığınızı ve şu anda bir probleminiz olmadığını düşündüğünüzde size inanıyorum ama bu sadece önemli değil)
Ruben Bartelink

@RubenBartelink Kabul ediyorum. Bu bir hack. Ne çözdüğü veya nasıl çözülmediği zaman bir şey yapan Voodoo kodu. Uygun bir çözüm isterdim.
Reactgular

1
Benim sorunum, stackoverflow.com/a/14933880/11635 üzerinde ekledi her şey oldukça spekülatif olmasıdır. Yapabilseydim, çoğaltma için -1 ve tesadüflerle spekülasyon / programlama için -1 veririm. Yağmurlama GC.Collecta) Sadece Kötü Tavsiye ve b) kilitli dirseklerin buraya dahil edilmeyi hak etmesine yetecek kadar yaygın bir genel neden değildir. Diğerlerinden birini seçin ve masum okuyucuların zihninde daha fazla karışıklık
ekmeyin

3
GC.WaitForPendingFinalizers () kullanın; GC.Collect () sonrasında; bu beklendiği gibi çalışacaktır.
Heiner

Emin değil, denenmemiş, ama belki de daha iyi bir usingifade ile bir şeyler yapmak olurdu , o zaman: 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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.