निर्देशिका को हटा नहीं सकते।


383

मैं .NET 3.5 का उपयोग कर रहा हूं, एक निर्देशिका को पुन: उपयोग करने की कोशिश कर रहा हूं:

Directory.Delete(myPath, true);

मेरी समझ यह है कि यह फेंक देना चाहिए यदि फ़ाइलें उपयोग में हैं या कोई अनुमति समस्या है, लेकिन अन्यथा इसे निर्देशिका और इसकी सभी सामग्री को हटा देना चाहिए।

हालाँकि, मुझे कभी-कभार यह मिलता है:

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

मुझे आश्चर्य नहीं है कि विधि कभी-कभी फेंकता है, लेकिन मैं इस विशेष संदेश को प्राप्त करने के लिए आश्चर्यचकित हूं जब पुनरावर्ती सच है। (मुझे पता है कि निर्देशिका खाली नहीं है।)

वहाँ एक कारण मैं AccessViolationException के बजाय यह देखना होगा?


13
आपको AccessViolationException नहीं दिखाई देगी - यह अमान्य पॉइंटर ऑपरेशन के लिए है, डिस्क एक्सेस के लिए नहीं।
जो व्हाइट

1
ऐसा लगता है कि IO मुद्दा केवल निर्देशिका के खाली न होने के अलावा, किसी तरह का खुला फ़ाइल हैंडल या कुछ और है। मैं पुनरावर्ती हटाने के विकल्प का उपयोग करने की कोशिश करूंगा, फिर IOException के लिए एक पकड़ में, किसी भी खुले फ़ाइल हैंडल को खोजता हूं और बंद करता हूं, फिर पुन: प्रयास करता हूं। इस बारे में चर्चा यहाँ है: stackoverflow.com/questions/177146/…
19

जवाबों:


231

संपादक का ध्यान दें: हालांकि इस उत्तर में कुछ उपयोगी जानकारी है, लेकिन यह कामकाज के बारे में तथ्यात्मक रूप से गलत है Directory.Delete। कृपया इस उत्तर के लिए टिप्पणियाँ, और इस प्रश्न के अन्य उत्तर पढ़ें।


मैं पहले इस समस्या में भाग गया।

समस्या की जड़ यह है कि यह फ़ंक्शन उन फ़ाइलों को नहीं हटाता है जो निर्देशिका संरचना के भीतर हैं। तो आपको जो करने की आवश्यकता होगी वह एक ऐसा फंक्शन बनाना है जो डायरेक्टरी स्ट्रक्चर के भीतर की सभी फाइल्स को डिलीट कर देता है फिर डायरेक्टरी को हटाने से पहले सभी डाइरेक्टरी को। मुझे पता है कि यह दूसरे पैरामीटर के खिलाफ है, लेकिन यह बहुत सुरक्षित दृष्टिकोण है। इसके अलावा, आप संभवतः फ़ाइलों को हटाने से पहले READ-ON तक पहुंच विशेषताओं को हटाना चाहते हैं। अन्यथा वह अपवाद खड़ा करेगा।

बस इस कोड को अपने प्रोजेक्ट में लगाओ।

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

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

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

    Directory.Delete(target_dir, false);
}

इसके अलावा, मेरे लिए मैं व्यक्तिगत रूप से मशीन के उन क्षेत्रों पर प्रतिबंध जोड़ता हूं जिन्हें हटाने की अनुमति है क्योंकि क्या आप चाहते हैं कि कोई व्यक्ति इस फ़ंक्शन को C:\WINDOWS (%WinDir%)या तो कॉल करे C:\


117
यह बकवास है। Directory.Delete (myPath, true) एक अधिभार है जो निर्देशिका संरचना के भीतर मौजूद सभी फ़ाइलों को हटा देता है। यदि आप गलत करना चाहते हैं, तो रयान एस उत्तर के साथ गलत करें।
सिग। टोलरेंज़ा

35
+1 क्योंकि Directory.Delete () अपने उपनिर्देशिका (पुनरावर्ती = सत्य के साथ) के अंदर फ़ाइलों को हटाता है, यह एक "IOException: निर्देशिका खाली नहीं है" यदि कोई उप-निर्देशिका या फ़ाइलों को केवल पढ़ने के लिए फेंकता है। इसलिए यह समाधान Directory.Delete () से बेहतर काम करता है
एंथनी ब्रीन

17
Directory.Delete(path, true)फाइलों को डिलीट नहीं करने वाला आपका बयान गलत है। MSDN msdn.microsoft.com/en-us/library/fxeahc5f.aspx
कॉन्स्टेंटिन

20
-1 क्या कोई स्पष्ट मार्कर लगा सकता है कि इस दृष्टिकोण की वैधता बहुत संदेह में है। यदि Directory.Delete(string,bool)विफल रहता है, तो कुछ बंद या गलत तरीके से प्रस्तुत किया गया है और ऐसी समस्या के सभी समाधान के लिए कोई एक आकार फिट नहीं है। लोगों को उनके संदर्भ में उस मुद्दे को संबोधित करने की जरूरत है और हम समस्या के हर विचार (रिट्रीट और अपवाद को निगलने के साथ) और एक अच्छे परिणाम की उम्मीद में एक बड़े बालों वाले फेंक को बढ़ा रहे हैं।
रूबेन बार्टलिंक

37
इस दृष्टिकोण से सावधान रहें यदि आपकी निर्देशिका को हटाने से आपके शॉर्टकट / प्रतीकात्मक लिंक अन्य फ़ोल्डरों से जुड़े हैं - तो आप और अधिक डिलीट कर सकते हैं, फिर आप उम्मीद कर सकते हैं
चाणक्य

182

यदि आप निर्देशिका को पुन: हटाने की कोशिश कर रहे हैं aऔर a\bएक्सप्लोरर में निर्देशिका खुली है, bतो हटा दी जाएगी , लेकिन आपको यह त्रुटि 'निर्देशिका खाली नहीं है' के लिए aमिलेगी , भले ही यह खाली हो जब आप जाते हैं और देखते हैं। किसी भी एप्लिकेशन (एक्सप्लोरर सहित) की वर्तमान निर्देशिका डायरेक्टरी को संभालती है । जब आप कॉल करते हैं Directory.Delete(true), तो यह नीचे से हटा दिया जाता है: bतब a। यदि bएक्सप्लोरर में खुला है, तो एक्सप्लोरर विलोपन का पता लगाएगा b, निर्देशिका को ऊपर की ओर बदल देगा cd ..और खुले हैंडल को साफ कर देगा। चूंकि फ़ाइल सिस्टम अतुल्यकालिक रूप से संचालित होता है, इसलिए Directory.Deleteएक्सप्लोरर के साथ संघर्ष के कारण ऑपरेशन विफल हो जाता है।

अधूरा हल

मैं मूल समाधान को जारी करने के लिए एक्सप्लोरर थ्रेड को हैंडल करने की अनुमति देने के विचार के साथ मूल समाधान को मूल रूप से निम्नलिखित समाधान पोस्ट करता हूं।

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

लेकिन यह केवल तभी काम करता है जब खुली निर्देशिका उस निर्देशिका का तत्काल बच्चा है जिसे आप हटा रहे हैं। यदि a\b\c\dExplorer में खुला है और आप इस पर उपयोग a, इस तकनीक को हटाने के बाद विफल हो जाएगा dऔर c

कुछ हद तक बेहतर उपाय

यह विधि एक गहरी निर्देशिका संरचना को हटाने का काम करेगी भले ही एक्सप्लोरर में निचले स्तर की निर्देशिका में से कोई एक खुली हो।

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

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

अपने दम पर काम करने के अतिरिक्त काम के बावजूद, हमें अभी भी संभालना हैUnauthorizedAccessException जो रास्ते में हो सकता है। यह स्पष्ट नहीं है कि पहला विलोपन का प्रयास दूसरे, सफल एक के लिए मार्ग प्रशस्त कर रहा है, या यदि यह केवल अपवाद को फेंकने / पकड़ने के द्वारा शुरू की गई समय की देरी है, जो फ़ाइल सिस्टम को पकड़ने की अनुमति देता है।

आप ब्लॉक Thread.Sleep(0)की शुरुआत में जोड़कर और विशेष परिस्थितियों में पकड़े गए अपवादों की संख्या को कम करने में सक्षम हो सकते हैं try। इसके अतिरिक्त, एक जोखिम है कि भारी सिस्टम लोड के तहत, आप दोनों Directory.Deleteप्रयासों के माध्यम से उड़ सकते हैं और असफल हो सकते हैं। इस समाधान पर अधिक मजबूत पुनरावर्ती विलोपन के लिए एक प्रारंभिक बिंदु पर विचार करें।

सामान्य उत्तर

यह समाधान केवल Windows Explorer के साथ सहभागिता की ख़ासियत को संबोधित करता है। यदि आप रॉक-सॉलिड डिलीट ऑपरेशन चाहते हैं, तो एक बात का ध्यान रखें कि कुछ भी (वायरस स्कैनर, जो भी हो) किसी भी समय आप जो भी डिलीट करने की कोशिश कर रहे हैं, उसका एक खुला हैंडल हो सकता है। इसलिए आपको बाद में फिर से प्रयास करना होगा। बाद में कितनी बार, और कितनी बार आप प्रयास करते हैं, यह इस बात पर निर्भर करता है कि वह वस्तु कितनी महत्वपूर्ण है। के रूप में MSDN इंगित करता है ,

मजबूत फ़ाइल पुनरावृत्ति कोड को फाइल सिस्टम की कई जटिलताओं को ध्यान में रखना चाहिए।

यह निर्दोष बयान, NTFS संदर्भ प्रलेखन के लिए केवल एक लिंक के साथ आपूर्ति की, अपने बाल खड़े करने के लिए चाहिए।

( संपादित करें : बहुत। यह उत्तर मूल रूप से केवल पहला, अधूरा समाधान था।)


11
यह डाइरेक्टरी निर्देशिका को दर्शाता है। पैलेट (पथ, सत्य), जबकि पथ या पथ के तहत एक फ़ोल्डर खुला है या विंडोज एक्सप्लोरर में चुना गया है, एक IOException फेंक देगा। विंडोज एक्सप्लोरर को बंद करना और मेरे मौजूदा कोड को फिर से काम करना / ठीक करने के लिए ऊपर दिए गए सुझाव / कैच को ठीक करना।
डेविड अल्परट

1
मैं यह नहीं बता सकता कि यह कैसे और क्यों काम करता है, लेकिन यह मेरे लिए काम करता है जबकि फ़ाइल विशेषताएँ सेट करना और अपना स्वयं का पुनरावर्ती कार्य लिखना नहीं था।
स्टिलगर

1
@CarlosLiu क्योंकि यह "एक्सप्लोरर को डायरेक्टरी हैंडल को जारी करने का मौका दे रहा है"
दिमित्री

4
क्या हो रहा है कि सिस्टम एक्सप्लोरर को "डायरेक्टरी हैंडल को रिलीज़ करने" के लिए कहता है, फिर डायरेक्ट्री को हटाने का प्रयास करता है। यदि निर्देशिका हैंडल को समय में हटाया नहीं गया था, तो एक अपवाद उठाया जाता है और catchब्लॉक निष्पादित किया जाता है (इस बीच, एक्सप्लोरर अभी भी निर्देशिका जारी कर रहा है, क्योंकि कोई कमांड ऐसा नहीं करने के लिए कहने के लिए भेजा गया है)। कॉल करना Thread.Sleep(0)आवश्यक हो सकता है या नहीं, क्योंकि catchब्लॉक ने पहले ही सिस्टम को थोड़ा और समय दिया है, लेकिन यह कम लागत के लिए थोड़ी अतिरिक्त सुरक्षा प्रदान करता है। उसके बाद, Deleteकहा जाता है, पहले से जारी निर्देशिका के साथ।
ज़ाचरी नाइबिल

1
@ पांडा वास्तव में केवल इस नींद (100) ने मेरे लिए काम किया। नींद (0) काम नहीं किया। मुझे नहीं पता कि क्या चल रहा है और इसे ठीक से कैसे हल किया जाए। मेरा मतलब है, क्या होगा अगर यह सर्वर लोड पर निर्भर करता है और भविष्य में 300 या 400 होना चाहिए? कैसे पता चलेगा कि एक और उचित तरीका होना चाहिए ...
रोमन

43

आगे जाने से पहले, निम्नलिखित कारणों की जाँच करें जो आपके नियंत्रण में हैं:

  • क्या फ़ोल्डर आपकी प्रक्रिया की वर्तमान निर्देशिका के रूप में सेट है? यदि हाँ, तो इसे पहले किसी और चीज़ में बदल दें।
  • क्या आपने उस फ़ोल्डर से कोई फ़ाइल खोली है (या DLL लोड की है)? (और इसे बंद / अनलोड करना भूल गया)

अन्यथा, अपने नियंत्रण के बाहर निम्नलिखित वैध कारणों की जांच करें:

  • उस फ़ोल्डर में केवल-पढ़ने के लिए फ़ाइल के रूप में चिह्नित हैं।
  • आपके पास उन फ़ाइलों में से कुछ को हटाने की अनुमति नहीं है।
  • फ़ाइल या सबफ़ोल्डर एक्सप्लोरर या किसी अन्य ऐप में खुला है।

यदि उपरोक्त में से कोई भी समस्या है, तो आपको यह समझना चाहिए कि अपने विलोपन कोड को सुधारने की कोशिश करने से पहले ऐसा क्यों होता है। क्या आपका ऐप रीड-ओनली या दुर्गम फाइलों को डिलीट कर रहा है? किसने उन्हें इस तरह से चिह्नित किया, और क्यों?

एक बार जब आप उपरोक्त कारणों से इंकार कर देते हैं, तब भी असफलताओं की संभावना होती है। यदि कोई भी किसी भी फ़ाइल या फ़ोल्डर को हटाए जा रहा है, तो हैंडल हटाने में विफल हो जाएगा, और कई कारण हैं कि कोई व्यक्ति फ़ोल्डर की गणना कर रहा है या इसकी फ़ाइलों को पढ़ रहा है:

  • अनुक्रमणिका खोजें
  • विरोधी वायरस
  • बैकअप सॉफ्टवेयर

सामान्य विफलताओं से निपटने के लिए सामान्य दृष्टिकोण, कई बार कोशिशों के बीच रुकना है। आप स्पष्ट रूप से हमेशा के लिए प्रयास नहीं करना चाहते हैं, इसलिए आपको निश्चित संख्या में प्रयासों के बाद हार माननी चाहिए और या तो अपवाद छोड़ देना चाहिए या त्रुटि को अनदेखा करना चाहिए। ऐशे ही:

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

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

मेरी राय में, इस तरह के एक सहायक का उपयोग सभी विलोपन के लिए किया जाना चाहिए क्योंकि सहज विफलताओं हमेशा संभव होती हैं। हालाँकि, आप अपने उपयोग के लिए इस कोड का उपयोग कर सकते हैं, न कि केवल आँख बंद करके।

मेरे एप्लिकेशन द्वारा जनरेट किए गए आंतरिक डेटा फ़ोल्डर के लिए मुझे स्थानीय विफलताओं का सामना करना पड़ा,% LocalAppData% के अंतर्गत, इसलिए मेरा विश्लेषण इस तरह है:

  1. मेरे एप्लिकेशन द्वारा फ़ोल्डर को पूरी तरह से नियंत्रित किया जाता है, और उपयोगकर्ता के पास उस फ़ोल्डर के अंदर केवल-पढ़ने योग्य या दुर्गम के रूप में चीजों को जाने और चिह्नित करने का कोई वैध कारण नहीं है, इसलिए मैं उस मामले को संभालने की कोशिश नहीं करता हूं।

  2. वहाँ कोई मूल्यवान उपयोगकर्ता-निर्मित सामान नहीं है, इसलिए गलती से किसी चीज़ को हटाने का कोई जोखिम नहीं है।

  3. आंतरिक डेटा फ़ोल्डर होने के नाते, मुझे उम्मीद नहीं है कि यह एक्सप्लोरर में खुला होगा, कम से कम मुझे विशेष रूप से मामले को संभालने की आवश्यकता नहीं है (यानी मैं समर्थन के माध्यम से उस मामले को ठीक से संभाल रहा हूं)।

  4. यदि सभी प्रयास विफल होते हैं, तो मैं त्रुटि को अनदेखा करने का चयन करता हूं। सबसे खराब स्थिति में, एप्लिकेशन कुछ नए संसाधनों को अनपैक करने में विफल रहता है, उपयोगकर्ता को समर्थन से संपर्क करने के लिए क्रैश करता है और संकेत देता है, जो मुझे स्वीकार्य है जब तक कि यह अक्सर नहीं होता है। या, यदि ऐप क्रैश नहीं होता है, तो यह कुछ पुराने डेटा को पीछे छोड़ देगा, जो फिर से मुझे स्वीकार्य है।

  5. मैं रिट्रीट्स को 500ms (50 * 10) तक सीमित करना चुनता हूं। यह एक मनमाना दहलीज है जो व्यवहार में काम करता है; मैं चाहता था कि थ्रेशोल्ड बहुत कम हो ताकि उपयोगकर्ता ऐप को मार न सकें, यह सोचकर कि उसने जवाब देना बंद कर दिया है। दूसरी ओर, मेरे फ़ोल्डर को संसाधित करने के लिए अपराधी के लिए आधा सेकंड का समय बहुत है। अन्य SO उत्तरों को देखते हुए, जो कभी-कभी Sleep(0)स्वीकार्य भी लगते हैं, बहुत कम उपयोगकर्ता कभी-कभी एकल रिट्री से अधिक अनुभव करेंगे।

  6. मैं हर 50ms पर पुन: प्रयास करता हूं, जो एक और मनमानी संख्या है। मुझे लगता है कि अगर किसी फ़ाइल को संसाधित (अनुक्रमित, चेक किया गया) किया जा रहा है, जब मैं इसे हटाने की कोशिश करता हूं, तो 50 मी सही समय के बारे में है कि मेरे मामले में प्रसंस्करण पूरा होने की उम्मीद है। इसके अलावा, 50ms एक ध्यान देने योग्य मंदी में परिणाम नहीं करने के लिए काफी छोटा है; फिर से, Sleep(0)कई मामलों में पर्याप्त लगता है, इसलिए हम बहुत अधिक देरी नहीं करना चाहते हैं।

  7. कोड किसी भी IO अपवादों पर पीछे हट जाता है। मुझे आमतौर पर% LocalAppData% तक पहुँचने वाले किसी भी अपवाद की उम्मीद नहीं है, इसलिए मैंने सादगी को चुना और वैध अपवाद होने की स्थिति में 500 मी देरी के जोखिम को स्वीकार किया। मैं उस सटीक अपवाद का पता लगाने का एक तरीका भी नहीं जानना चाहता था जिस पर मैं फिर से प्रयास करना चाहता हूं।


7
PPS कुछ महीने बाद, मुझे यह बताते हुए खुशी हो रही है कि इस (कुछ पागल) कोड के टुकड़े ने पूरी तरह से समस्या हल कर दी है। इस समस्या के बारे में समर्थन अनुरोध शून्य से (लगभग 1-2 प्रति सप्ताह) हैं।
एंड्री टारनटोसव

1
+0 जबकि यह अधिक मजबूत और कम है 'यहाँ यह है; आपके लिए सही समाधान 'से अधिक stackoverflow.com/a/7518831/11635 , मेरे लिए वही लागू होता है - संयोग से प्रोग्रामिंग - देखभाल के साथ संभाल। आपके कोड में सन्निहित एक उपयोगी बात यह है कि यदि आप एक रिट्री करने जा रहे हैं, तो आपको यह विचार करने की आवश्यकता है कि आप इस प्रयास की अस्पष्टता के साथ दौड़ में हैं कि क्या पिछले प्रयास के बाद से डायरेक्टरी 'गॉन' हुई है या Directory.Existsनहीं। इसका समाधान न करें।]
रूबेन बार्टलिंक

1
इसे प्यार करो ... मुझे नहीं पता कि मैं क्या कर रहा हूं, यह हमेशा मेरे लिए एक दर्द बिंदु है ... लेकिन ऐसा नहीं है क्योंकि मेरे पास एक्सप्लोरर में निर्देशिका खुली है ... इस बारे में इंटरनेट पर ज्यादा हंगामा नहीं -या-कम बग ... कम से कम मेरे और एंड्री के पास इससे निपटने का एक तरीका है :)
TCC

2
@RubenBartelink ठीक है, इसलिए मुझे लगता है कि हम इस पर सहमत हो सकते हैं: कोड का एक टुकड़ा पोस्ट करना जो एक विशिष्ट ऐप के लिए काम करता है (और इसका मतलब कभी भी हर मामले के लिए उपयुक्त नहीं था) क्योंकि एसओ का जवाब कई नौसिखियों के लिए एक असंतोष होने वाला है और / या अज्ञानी डेवलपर्स। मैंने इसे अनुकूलन के लिए एक शुरुआती बिंदु के रूप में दिया था, लेकिन हाँ, कुछ लोग इसका उपयोग करने जा रहे हैं, और यह एक बुरी बात है।
एंड्री टारनटोसव

2
@nopara आपको तुलना की आवश्यकता नहीं है; यदि हम पाश से बाहर हैं, तो हम असफल रहे हैं और हाँ, कई मामलों में आप अपवाद को फेंकना चाहेंगे, फिर उपयोगकर्ता द्वारा दिखाई देने वाले संदेश के साथ, स्टैक तक उपयुक्त त्रुटि हैंडलिंग कोड जोड़ें।
एंड्रे टारनटोसव

18

आधुनिक Async उत्तर

स्वीकृत उत्तर केवल स्पष्ट गलत है, यह कुछ लोगों के लिए काम कर सकता है क्योंकि डिस्क से फाइलें प्राप्त करने में लगने वाला समय फाइलों को लॉक करने वाले जो कुछ भी है, उसे मुक्त कर देता है। तथ्य यह है, ऐसा इसलिए होता है क्योंकि फाइलें किसी अन्य प्रक्रिया / धारा / क्रिया द्वारा लॉक हो जाती हैं। अन्य उत्तर Thread.Sleepकुछ समय के बाद निर्देशिका को हटाने के लिए (Yuck) का उपयोग करते हैं । इस प्रश्न को और अधिक आधुनिक उत्तर के साथ फिर से समझने की आवश्यकता है।

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

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

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

    return false;
}

यूनिट टेस्ट

ये परीक्षण एक उदाहरण दिखाते हैं कि कैसे एक बंद फ़ाइल Directory.Deleteविफल होने का कारण बन सकती है और कैसे TryDeleteDirectoryऊपर की विधि समस्या को ठीक करती है।

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

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

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

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

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

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

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

क्या आप "आधुनिक" के अर्थ से विस्तार कर सकते हैं? आपके दृष्टिकोण के क्या लाभ हैं? दूसरे लोग आपकी राय में गलत क्यों हैं?
टाइनीराकून

1
दूसरे गलत नहीं हैं। वे बस पुराने API का उपयोग करते हैं जैसे Thread.Sleepकि आपको आज से बचना चाहिए और इसके बजाय async/ के awaitसाथ उपयोग करना चाहिए Task.Delay। यह समझ में आता है, यह एक बहुत पुराना सवाल है।
मुहम्मद रेहान सईद

यह दृष्टिकोण VB.Net (कम से कम बहुत शाब्दिक लाइन-फॉर-लाइन रूपांतरण के साथ नहीं) के कारण काम नहीं करेगाBC36943 'Await' cannot be used inside a 'Catch' statement, a 'Finally' statement, or a 'SyncLock' statement.
amonroejj

@amonroejj आप एक पुराने संस्करण का उपयोग कर रहे होंगे। वह तय हो गया था।
मुहम्मद रेहान सईद

वापसी के बजाय थोड़ा सुधार सही if (!Directory.Exists(directoryPath)) { return true; } await Task.Delay(millisecondsDelay); है जब तक कि निर्देशिका वास्तव में इंतजार न करे
fuchs777

16

एक महत्वपूर्ण बात जिसका उल्लेख किया जाना चाहिए (मैंने इसे एक टिप्पणी के रूप में जोड़ा है लेकिन मुझे इसकी अनुमति नहीं है) यह है कि अधिभार का व्यवहार .NET 3.5 से बदल कर .NET 4.0 हो गया है।

Directory.Delete(myPath, true);

.NET 4.0 से शुरू होकर यह फोल्डर में मौजूद फाइल्स को डिलीट करता है लेकिन 3.5 में नहीं। इसे MSDN प्रलेखन में भी देखा जा सकता है।

.NET 4.0

निर्दिष्ट निर्देशिका को हटाता है और, यदि संकेत दिया गया है, तो निर्देशिका में कोई उपनिर्देशिका और फाइलें।

.NET 3.5

खाली निर्देशिका को हटाता है और, यदि संकेत दिया जाता है, तो निर्देशिका में कोई उपनिर्देशिका और फाइलें।


3
मुझे लगता है कि यह केवल एक दस्तावेज़ीकरण परिवर्तन है ... यदि यह केवल "खाली निर्देशिका" को हटाता है, तो 2 डिग्री पैरामीटर के साथ निर्देशिका में फ़ाइलों को हटाने का क्या मतलब होगा? अगर यह खाली है तो फाइलें नहीं हैं ...
पिस्सु

मुझे डर है कि आप गलत मान रहे हैं। मैंने इसे दोनों फ्रेमवर्क संस्करणों के साथ कोड का परीक्षण करने के बाद पोस्ट किया है। 3.5 में एक गैर-खाली फ़ोल्डर को हटाने से अपवाद फेंक दिया जाएगा।
jettatore

15

मुझे डेल्फी के तहत बहुत ही समस्या थी। और अंतिम परिणाम यह था कि मेरा अपना आवेदन उस निर्देशिका को लॉक कर रहा था जिसे मैं हटाना चाहता था। किसी तरह निर्देशिका बंद हो गई जब मैं इसे लिख रहा था (कुछ अस्थायी फाइलें)।

कैच 22 था, मैंने इसे हटाने से पहले माता-पिता के लिए एक साधारण परिवर्तन निर्देशिका बनाई ।


6
+1 अब ऐसा कुछ है जो Directory.Delete के लिए msdn उल्लेख करता है!
बार्टनलिंक

3
पूर्ण स्रोत कोड नमूने के साथ कोई अंतिम समाधान इसके बारे में काम कर रहा है?
किकेनेट

11

मुझे आश्चर्य है कि इस सरल गैर-पुनरावर्ती विधि के बारे में किसी ने भी नहीं सोचा, जो केवल फ़ाइलों को पढ़ने की निर्देशिका को हटा सकता है, उनमें से प्रत्येक की केवल विशेषता को बदलने की आवश्यकता के बिना।

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

(पल-पल एक cmd विंडो को आग न लगाने के लिए थोड़ा बदलें, जो पूरे इंटरनेट पर उपलब्ध है)


हमारे साथ साझा करने के लिए अच्छा है, लेकिन क्या आप इतने दयालु होंगे कि नेट पर खोज करने के लिए हमें प्रेरित करने के बजाय, cmd विंडो को फायर करने से रोकने के लिए आवश्यक थोड़ा सा बदलाव शामिल करना होगा?
थंडरग्रो

यह काम नहीं करता है। उसी स्थिति में जहां मैं कमांड प्रॉम्प्ट या एक्सप्लोरर से फ़ाइल को हटा सकता हूं, इस कोड का उपयोग करके rmdir से बाहर निकलने का कोड 145 दिया जाता है जो "निर्देशिका खाली नहीं है" का अनुवाद करता है। यह निर्देशिका को खाली छोड़ देता है, लेकिन फिर भी निर्देशिका की तरह होता है। बिल्कुल इसी तरह। निर्देशिका ("", सच)
केविन कूलोमेबे

@ केविन कूलोमबे, हम्म ... क्या आप सुनिश्चित हैं कि आप / s / q स्विच का उपयोग कर रहे हैं?
पीयूष सोनी

1
@KevinCoulombe: हाँ, यह उन COM घटक होना चाहिए। जब मैं सादे पुराने सी # के माध्यम से कोशिश करता हूं, तो यह काम करता है और यह निर्देशिका को फ़ाइलों के साथ हटाता है (केवल या गैर-पढ़े गए लोगों को पढ़ें)।
पीयूष सोनी

5
यदि आप फ्रेमवर्क में बाहरी घटकों पर निर्भर होना शुरू करते हैं तो यह "आदर्श से कम" विचार coz है जो अब पोर्टेबल नहीं है (या अधिक कठिन)। क्या होगा अगर वहाँ exe नहीं हैं? या / विकल्प बदल गया? यदि जेरेमी एडवर्ड्स द्वारा समाधान काम करता है, तो इसे
आईएमएचओ

11

आप त्रुटि को चलाकर पुन: उत्पन्न कर सकते हैं:

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

निर्देशिका 'बी' को हटाने की कोशिश करते समय, यह IOException "निर्देशिका खाली नहीं है" फेंकता है। यह बेवकूफी है क्योंकि हमने केवल निर्देशिका 'c' को हटा दिया है।

मेरी समझ से, स्पष्टीकरण यह है कि निर्देशिका 'c' को हटाए जाने पर मुहर लगाई जाती है। लेकिन सिस्टम में अभी तक डिलीट नहीं किया गया है। सिस्टम ने जवाब दिया है कि काम किया जाता है, जबकि वास्तव में, यह अभी भी प्रसंस्करण है। सिस्टम शायद प्रतीक्षा करता है फ़ाइल एक्सप्लोरर ने डिलीट करने के लिए पैरेंट डायरेक्टरी पर फोकस किया है।

यदि आप हटाएं फ़ंक्शन ( http://referencesource.microsoft.com/#mscorlib/system/io/directory.cs ) के स्रोत कोड को देखते हैं, तो आप देखेंगे कि यह मूल Win32Native.RemoveDirectory फ़ंक्शन का उपयोग करता है। यह मत करो-प्रतीक्षा व्यवहार यहाँ नोट किया गया है:

RemoveDirectory फ़ंक्शन पास पर विलोपन के लिए एक निर्देशिका को चिह्नित करता है। इसलिए, निर्देशिका को हटाया नहीं जाता है जब तक कि निर्देशिका के अंतिम हैंडल को बंद नहीं किया जाता है।

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

नींद और पुनः प्रयास इसका समाधान है। Ryascl का समाधान cf करें।


8

एक्सप्लोरर शेल में ऐसा करने में सक्षम होने के बावजूद मुझे उपयोगकर्ता प्रोफ़ाइल निर्देशिकाओं (C: \ दस्तावेज़ों और सेटिंग्स में) को हटाने की अजीब समस्या थी।

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

यह मेरे लिए कोई मायने नहीं रखता है कि एक निर्देशिका में "फ़ाइल" ऑपरेशन क्या करता है, लेकिन मुझे पता है कि यह काम करता है और यह मेरे लिए पर्याप्त है!


2
फिर भी कोई उम्मीद नहीं है, जब निर्देशिका में बहुत सारी फाइलें हैं और एक्सप्लोरर उन फाइलों वाले फ़ोल्डर को खोल रहा है।
देखता है

3

: इस जवाब पर आधारित है https://stackoverflow.com/a/1703799/184528 । मेरे कोड के साथ अंतर यह है कि हम केवल निर्देशिका को कॉल करते समय कई उप-निर्देशिका और फ़ाइलों को हटाते हैं। पहले प्रयास पर Directory.Delete विफल रहता है (जो एक निर्देशिका को देखने वाले विंडोज़ एक्सप्लोरर के कारण हो सकता है)।

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

तो अगर वहाँ एक फ़ोल्डर को हटाने के लिए कैसे माना जाता है UnauthorizedAccessException? यह बस फेंक देंगे, फिर से। और फिर। और फिर से ... क्योंकि हर बार यह catchसमारोह में जाना और फिर से कॉल करना है। A Thread.Sleep(0);आपकी अनुमतियां नहीं बदलता है। यह केवल त्रुटि को लॉग इन करना चाहिए और उस बिंदु पर इनायत से विफल होना चाहिए। और यह लूप तब तक जारी रहेगा जब तक (उप) निर्देशिका खुली है - यह इसे प्रोग्रामेटिक रूप से बंद नहीं करता है। क्या हम इसे तब तक करने के लिए तैयार हैं जब तक कि इसे उन चीजों को खुला छोड़ दिया जाए? क्या कोई बेहतर तरीका है?
vapcguy

यदि UnauthorizedAccessExceptionयह है तो यह मैन्युअल रूप से प्रत्येक फ़ाइल को मैन्युअल रूप से हटाने का प्रयास करेगा। इसलिए यह निर्देशिका संरचना में आगे बढ़ते हुए प्रगति करना जारी रखता है। हां, संभावित रूप से प्रत्येक फ़ाइल और निर्देशिका एक ही अपवाद को फेंक देगी, लेकिन यह केवल इसलिए भी हो सकती है क्योंकि एक्सप्लोरर इसे संभाल रहा है (देखें stackoverflow.com/a/1703799/184528 ) मैं "सेकंडआर्ट" को "tryAgain" बदल दूंगा इसे और अधिक स्पष्ट करने के लिए।
cdiggins

अधिक संक्षेप में जवाब देने के लिए, यह "सच" गुजरता है और एक अलग कोड पथ निष्पादित करता है।
cdiggins

ठीक है, अपना संपादन देखा, लेकिन मेरी बात फ़ाइलों को हटाने के साथ नहीं है, लेकिन निर्देशिका को हटाने के साथ है। मैंने कुछ कोड लिखा है जहां मैं Process.Kill()किसी भी प्रक्रिया पर अनिवार्य रूप से कर सकता हूं एक फ़ाइल को लॉक किया जा सकता है, और फ़ाइलों को हटा सकता है। समस्या मैं चला रहा हूँ जब एक निर्देशिका को हटा रहा है जहाँ उन फ़ाइलों में से एक अभी भी खुला था (देखें stackoverflow.com/questions/41841590/… )। तो इस लूप के माध्यम से वापस जा रहे हैं, कोई फर्क नहीं पड़ता कि यह क्या कर रहा है, अगर यह Directory.Delete()उस फ़ोल्डर पर फिर से करता है, तो यह अभी भी विफल हो जाएगा यदि उस हैंडल को जारी नहीं किया जा सकता है।
vapcguy

और UnauthorizedAccessExceptionफ़ाइलों को हटाने के बाद से ऐसा ही होगा (यह मानते हुए भी अनुमति दी गई थी, क्योंकि उस कोड को प्राप्त करने के लिए, यह विफल रहा है Directory.Delete()) जादुई रूप से आपको निर्देशिका को हटाने की अनुमति नहीं देता है।
vapcguy

3

उपरोक्त समाधानों में से किसी ने भी मेरे लिए अच्छा काम नहीं किया। मैं नीचे के रूप में @ryascl समाधान के एक संपादित संस्करण का उपयोग करके समाप्त हुआ:

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

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

2

क्या यह संभव है कि आपके पास एक दौड़ की स्थिति है जहां एक और धागा या प्रक्रिया निर्देशिका में फाइलें जोड़ रही है:

अनुक्रम होगा:

गलाने की प्रक्रिया A:

  1. निर्देशिका खाली करें
  2. अब (अब खाली) निर्देशिका हटाएं।

अगर कोई और 1 और 2 के बीच कोई फ़ाइल जोड़ता है, तो शायद 2 सूचीबद्ध अपवाद को फेंक देगा?


2

मैंने निर्देशिका को हटाने के साथ इस समस्या और अन्य अपवादों को हल करने के लिए कुछ घंटे बिताए हैं। यह मेरा समाधान है

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

इस कोड में छोटी देरी है, जो मेरे आवेदन के लिए महत्वपूर्ण नहीं है। लेकिन सावधान रहें, देरी आपके लिए एक समस्या हो सकती है यदि आपके पास उस निर्देशिका के अंदर बहुत सारी उपनिर्देशिकाएँ हैं जिन्हें आप हटाना चाहते हैं।


8
-1 क्या देरी है? संयोग से कोई प्रोग्रामिंग कृपया!
रूबेन बार्टलिंक

1
@ रूबेन ने नहीं कहा कि आप इसके बारे में गलत हैं। मैंने सिर्फ यह कहा है कि इसे सिर्फ इस लिए नीचा दिखाना एक कठोर सजा है। मैं आपसे सहमत हूं, हालांकि, 4 अपवोट्स के परिणामस्वरूप 4 डाउनवोट्स नहीं थे। मैं आपकी टिप्पणी को भी
अपवाहित करूंगा

1
@RubenBartelink और अन्य: जबकि मैं विशेष रूप से इस कोड को पसंद नहीं करता (मैंने एक समान दृष्टिकोण के साथ एक और समाधान पोस्ट किया है), यहां देरी उचित है। समस्या एप्लिकेशन के नियंत्रण के बाहर होने की संभावना है; शायद एक अन्य ऐप एफएस को समय-समय पर बचाता है, इस प्रकार फ़ोल्डर को कम समय के लिए लॉक कर देता है। विलंब समस्या को हल करता है, बग रिपोर्ट को शून्य तक गिना जाता है। अगर हमारे पास कोई भ्रामक विचार नहीं है तो मूल कारण कौन है?
एंड्री टारनटोसव

1
@RubenBartelink वास्तव में, जब आप इसके बारे में सोचते हैं, तो NTFS निर्देशिका विलोपन के दौरान देरी और रिट्रीट दृष्टिकोण का उपयोग नहीं करना यहां एक गैर जिम्मेदाराना समाधान है। किसी भी प्रकार की चल रही फ़ाइल ट्रैवर्सल विलोपन को अवरुद्ध करती है, इसलिए यह जल्द या बाद में विफल होने के लिए बाध्य है। और आप अपने फ़ोल्डर से बाहर रहने के लिए सभी तृतीय-पक्ष खोज, बैकअप, एंटीवायरस और फ़ाइल प्रबंधन टूल की अपेक्षा नहीं कर सकते।
एंड्री टारनटोसव

1
@RubenBartelink एक और पूर्व।, कहते हैं कि आप 100ms की देरी करते हैं, और लक्ष्य PC पर किसी भी सॉफ़्टवेयर का उच्चतम लॉक समय AV सॉफ़्टवेयर = 90ms है। कहें कि इसमें बैकअप सॉफ़्टवेयर भी है जो 70ms के लिए फ़ाइलों को लॉक करता है। अब एवी एक फ़ाइल को लॉक करता है, आपका ऐप 100ms का इंतजार करता है, जो सामान्य रूप से ठीक है, लेकिन फिर एक और लॉक का सामना करता है क्योंकि बैकअप सॉफ्टवेयर एवी स्कैन के 70ms के निशान पर फ़ाइल को हथियाना शुरू कर देता है, और इसलिए फ़ाइल को रिलीज़ करने के लिए एक और 40ms लगेगा। इसलिए, जबकि AV सॉफ़्टवेयर अधिक समय लेता है और आपके 100ms सामान्य रूप से 2 ऐप्स से अधिक लंबे होते हैं, तब भी आपको बीच में शुरू होने पर इसका हिसाब देना होगा।
vapcguy

2

पुनरावर्ती निर्देशिका विलोपन जो फ़ाइलों को नहीं हटाता है निश्चित रूप से अप्रत्याशित है। उस के लिए मेरा फिक्स:

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

मुझे ऐसे मामलों का अनुभव हुआ जहां इसने मदद की, लेकिन आम तौर पर, Directory.Delete mssn में प्रलेखित के रूप में पुनरावर्ती विलोपन पर निर्देशिकाओं के अंदर फ़ाइलों को हटा देता है ।

समय-समय पर मैं इस अनियमित व्यवहार का सामना विंडोज एक्सप्लोरर के एक उपयोगकर्ता के रूप में भी करता हूं: कभी-कभी मैं एक फ़ोल्डर नहीं हटा सकता (ऐसा लगता है कि निरर्थक संदेश "एक्सेस निषेध" है) लेकिन जब मैं नीचे ड्रिल करता हूं और निचले आइटम हटाता हूं तो मैं ऊपरी हटा सकता हूं साथ ही आइटम। इसलिए मुझे लगता है कि ओएस ओएस विसंगति के ऊपर दिए गए कोड - बेस क्लास लाइब्रेरी इश्यू के साथ नहीं।


1

निर्देशिका या इसमें एक फ़ाइल बंद है और इसे हटाया नहीं जा सकता है। अपराधी को ढूंढें जो इसे बंद करता है और देखें कि क्या आप इसे समाप्त कर सकते हैं।


T1000 उपयोगकर्ता के साथ फ़ोल्डर-खुला: "आप समाप्त हो गए हैं!"
vapcguy

1

ऐसा प्रतीत होता है कि Windows Explorer में चयनित पथ या सबफ़ोल्डर Directory.Delete (पथ, सत्य) के एक एकल निष्पादन को अवरुद्ध करने के लिए पर्याप्त है, एक IOException को फेंकना जैसा कि ऊपर वर्णित है और Windows Explorer को मूल फ़ोल्डर में बूट करने और संसाधित करने के बजाय मर रहा है। अपेक्षित होना।


ऐसा प्रतीत होता है कि यह मेरी समस्या है। जैसे ही मैंने एक्सप्लोरर को बंद किया और फिर से चला गया, कोई अपवाद नहीं। यहां तक ​​कि माता-पिता के माता-पिता का चयन करना पर्याप्त नहीं था। मुझे वास्तव में एक्सप्लोरर को बंद करना पड़ा।
स्कॉट मार्लो

हां, ऐसा होता है और यह एक कारण है। तो किसी भी विचार कैसे प्रोग्राम के साथ सौदा करने के लिए, या जवाब है हमेशा सुनिश्चित करने के लिए कि सभी 1000 उपयोगकर्ताओं के पास वह फ़ोल्डर बंद है?
vapcguy

1

मुझे आज यह समस्या थी। यह इसलिए हो रहा था क्योंकि मेरे पास निर्देशिका के लिए विंडोज़ एक्सप्लोरर खुला था जिसे हटाने की कोशिश की जा रही थी, जिससे पुनरावर्ती कॉल विफल हो गई और इस तरह IOException। सुनिश्चित करें कि निर्देशिका के लिए कोई हैंडल खुला नहीं है।

इसके अलावा, MSDN स्पष्ट है कि आपको अपनी खुद की पुनरावृत्ति लिखने की ज़रूरत नहीं है: http://msdn.microsoft.com/en-us/library/fxeahc5f.aspx


1

TFS2012 के साथ बिल्ड सर्वर पर विंडोज वर्कफ़्लो फ़ाउंडेशन के साथ मेरी यही समस्या है। आंतरिक रूप से, वर्कफ़्लो नामक निर्देशिका। यह हमारे मामले से संबंधित नेटवर्क प्रतीत होता है।

नवीनतम बायनेरिज़ के साथ फिर से बनाने और इसे फिर से आबाद करने से पहले हम एक नेटवर्क शेयर पर एक बाइनरी ड्रॉप फ़ोल्डर को हटा रहे थे। हर दूसरा निर्माण विफल होगा। असफल निर्माण के बाद ड्रॉप फ़ोल्डर को खोलते समय, फ़ोल्डर खाली था, जो इंगित करता है कि Directory.Delete () कॉल का हर पहलू वास्तव में निर्देशिका को हटाने के अलावा सफल था।

समस्या नेटवर्क फ़ाइल संचार की अतुल्यकालिक प्रकृति के कारण प्रतीत होती है। बिल्ड सर्वर ने फ़ाइल सर्वर को सभी फ़ाइलों को हटाने के लिए कहा और फ़ाइल सर्वर ने बताया कि यह पूरी तरह से समाप्त नहीं होने के बावजूद भी था। तब बिल्ड सर्वर ने अनुरोध किया कि निर्देशिका को हटा दिया जाए और फ़ाइल सर्वर ने अनुरोध को अस्वीकार कर दिया क्योंकि यह फ़ाइलों को पूरी तरह से समाप्त नहीं कर पाया था।

हमारे मामले में दो संभावित समाधान:

  • प्रत्येक चरण के बीच देरी और सत्यापन के साथ हमारे अपने कोड में पुनरावर्ती विलोपन का निर्माण करें
  • IOException के बाद X बार तक पुन: प्रयास करें, फिर से प्रयास करने से पहले एक देरी दे

उत्तरार्द्ध विधि त्वरित और गंदी है, लेकिन चाल करने के लिए लगता है।


1

यह FileChangesNotifications के कारण है

यह ASP.NET 2.0 के बाद से होता है। जब आप किसी एप्लिकेशन के भीतर कुछ फ़ोल्डर हटाते हैं, तो वह फिर से चालू हो जाता हैASP.NET हेल्थ मॉनिटरिंग का उपयोग करके आप इसे स्वयं देख सकते हैं ।

बस इस कोड को अपने web.config / configuration / system.web में जोड़ें:

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


इसके बाद चेक आउट करें Windows Log -> Application। क्या हो रहा है:

जब आप फ़ोल्डर को हटाते हैं, यदि कोई उप-फ़ोल्डर है, तो Delete(path, true)पहले उप-फ़ोल्डर को हटाता है। FileChangesMonitor को हटाने और अपने ऐप को बंद करने के बारे में जानने के लिए यह पर्याप्त है। इस बीच आपकी मुख्य निर्देशिका अभी तक नहीं हटाई गई है। यह लॉग से घटना है:


यहां छवि विवरण दर्ज करें


Delete() अपना काम पूरा नहीं किया और क्योंकि ऐप बंद हो रहा है, यह एक अपवाद उठाता है:

यहां छवि विवरण दर्ज करें

जब आपके पास उस फ़ोल्डर में कोई सबफ़ोल्डर नहीं होता है जिसे आप हटा रहे हैं, हटाएं () बस सभी फ़ाइलों को हटा देता है और उस फ़ोल्डर को, ऐप को भी पुनरारंभ किया जा रहा है, लेकिन आपको कोई अपवाद नहीं मिलता है , क्योंकि ऐप पुनरारंभ करने से कुछ भी बाधित नहीं होता है। लेकिन फिर भी, आप सभी इन-प्रोसेस सत्र खो देते हैं, एप्लिकेशन पुनः आरंभ करने पर अनुरोधों का जवाब नहीं देता है, आदि।

अब क्या?

इस व्यवहार को अक्षम करने के लिए कुछ वर्कअराउंड और ट्वीक्स हैं, निर्देशिका जंक्शन , रजिस्ट्री के साथ एफसीएन को बंद करना , रिफ्लेक्शन का उपयोग करके फाइलचैनजेसमैटर को रोकना (क्योंकि कोई उजागर विधि नहीं है) , लेकिन वे सभी सही नहीं लगते हैं, क्योंकि एफसीएन एक के लिए है कारण। यह आपके ऐप की संरचना की देखभाल कर रहा है , जो आपके डेटा की संरचना नहीं है । संक्षिप्त उत्तर है: उन फ़ोल्डरों को रखें जिन्हें आप अपने ऐप से बाहर हटाना चाहते हैं। FileChangesMonitor को कोई नोटिफिकेशन नहीं मिलेगा और आपका ऐप हर बार रीस्टार्ट नहीं होगा। आपको कोई अपवाद नहीं मिलेगा। उन्हें वेब से दिखाई देने के लिए दो तरीके हैं:

  1. एक कंट्रोलर बनाएं जो इनकमिंग कॉल्स को हैंडल करता है और फिर एक ऐप के बाहर फ़ोल्डर (wwwroot के बाहर) को पढ़कर फाइलों को वापस करता है।

  2. यदि आपका प्रोजेक्ट बड़ा है और प्रदर्शन सबसे महत्वपूर्ण है, तो स्थिर सामग्री परोसने के लिए अलग से छोटा और तेज़ वेबसर्वर सेट करें। इस प्रकार आप IIS को उसके विशिष्ट कार्य पर छोड़ देंगे। यह एक ही मशीन पर हो सकता है (विंडोज के लिए आम) या दूसरी मशीन (लिनक्स के लिए नेग्नेक्स)। अच्छी खबर यह है कि आपको लिनक्स पर स्थिर सामग्री सर्वर स्थापित करने के लिए अतिरिक्त Microsoft लाइसेंस का भुगतान करने की आवश्यकता नहीं है।

उम्मीद है की यह मदद करेगा।


1

जैसा कि ऊपर "स्वीकार किए जाते हैं" समाधान का उल्लेख पुनरावृत्ति बिंदुओं पर विफल रहता है - फिर भी लोग इसे अभी भी चिह्नित करते हैं (???) एक बहुत छोटा समाधान है जो ठीक से कार्यक्षमता की नकल करता है:

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

मुझे पता है, बाद में बताई गई अनुमतियों के मामलों को संभालता नहीं है, लेकिन सभी इरादों और उद्देश्यों के लिए FAR BETTER मूल / स्टॉक Directory.Delete () - और बहुत कम कोड के साथ अपेक्षित कार्यक्षमता प्रदान करता है

आप सुरक्षित रूप से प्रसंस्करण पर ले जा सकते हैं क्योंकि पुराना डायर रास्ते से बाहर हो जाएगा ... भले ही नहीं गया हो, क्योंकि 'फाइल सिस्टम अभी भी पकड़ रहा है' (या जो किसी भी बहाने एमएस ने एक टूटी हुई फ़ंक्शन प्रदान करने के लिए दिया था)

एक लाभ के रूप में, यदि आप जानते हैं कि आपकी लक्षित निर्देशिका बड़ी / गहरी है और प्रतीक्षा नहीं करना चाहते (या अपवादों से परेशान) अंतिम पंक्ति को इसके साथ प्रतिस्थापित किया जा सकता है:

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

आप अभी भी काम करने के लिए सुरक्षित हैं।


2
क्या आपके असाइनमेंट को सरल बनाया जा सकता है: string tfilename = Path.Combine (Path.GetDirectoryName (लक्ष्य), Path.GetRandomFileName ());
पीट

1
मुझे पीट से सहमत होना होगा। कोड के रूप में लिखा विभाजक नहीं जोड़ देगा। इसने मेरी राह ली \\server\C$\dirऔर इसे बनाया \\server\C$asf.yuw। परिणामस्वरूप मुझे एक त्रुटि मिली Directory.Move()- Source and destination path must have identical roots. Move will not work across volumes. काम ठीक ठीक एक बार जब मैंने पीट के कोड का उपयोग किया, तो न तो उस समय के लिए संभालती है जब लॉक की गई फाइलें या खुली निर्देशिका होती हैं-इसलिए यह कभी भी ThreadPoolकमांड को नहीं मिलती है ।
vapcguy

चेतावनी: इस उत्तर का उपयोग केवल पुनरावर्ती = सत्य के साथ किया जाना चाहिए। गलत होने पर, यह निर्देशिका को स्थानांतरित कर देगा भले ही वह खाली न हो। जो एक बग होगा; उस मामले में सही व्यवहार एक अपवाद फेंकने के लिए है, और निर्देशिका को छोड़ दें जैसा कि यह था।
टूलमेकरसैट

1

यह समस्या विंडोज पर तब दिखाई दे सकती है जब किसी डायरेक्टरी में (या किसी भी उपनिर्देशिका में) फाइलें होती हैं, जो पथ की लंबाई 260 प्रतीकों से अधिक है।

ऐसे मामलों में आपको \\\\?\C:\mydirइसके बजाय हटाने की आवश्यकता है C:\mydir। 260 प्रतीकों की सीमा के बारे में आप यहां पढ़ सकते हैं ।


1

मैं इस सहस्राब्दी तकनीक से हल हुआ (आप थ्रेड को छोड़ सकते हैं। पकड़ में ही सो जाएं)

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

यदि आपके एप्लिकेशन (या किसी अन्य एप्लिकेशन की) वर्तमान निर्देशिका वह है जिसे आप हटाने की कोशिश कर रहे हैं, तो यह एक्सेस उल्लंघन त्रुटि नहीं होगी, लेकिन एक निर्देशिका खाली नहीं है। सुनिश्चित करें कि यह वर्तमान निर्देशिका को बदलकर आपका अपना आवेदन नहीं है; यह भी सुनिश्चित करें कि निर्देशिका किसी अन्य प्रोग्राम (जैसे वर्ड, एक्सेल, टोटल कमांडर, आदि) में खुली नहीं है। अधिकांश प्रोग्राम खोले गए अंतिम फ़ाइल की निर्देशिका के लिए होंगे, जो इसका कारण बनेंगे।


0

नेटवर्क फ़ाइलों के मामले में, Directory.DeleteHelper (पुनरावर्ती: = सत्य) IOException का कारण हो सकता है जो फ़ाइल को हटाने की देरी के कारण होता है


0

मुझे लगता है कि कुछ स्ट्रीम से एक फाइल खुली हुई है जिसके बारे में आपको पता नहीं है कि मुझे एक ही समस्या थी और इसे उन सभी धाराओं को बंद करके हल किया गया था, जहां निर्देशिका को इंगित करने के लिए मैं हटाना चाहता था।


0

यह त्रुटि तब होती है जब किसी फ़ाइल या निर्देशिका को इन-यूज़ माना जाता है। यह एक भ्रामक त्रुटि है। यह देखने के लिए जांचें कि क्या आपके पास ट्री में किसी डायरेक्टरी के लिए कोई एक्सप्लोरर विंडो या कमांड-लाइन विंडो खुली है, या कोई प्रोग्राम जो उस ट्री में फाइल का उपयोग कर रहा है।


0

मैंने बताई गई समस्या का एक संभव उदाहरण हल किया जब विधियाँ इस प्रकार थीं और इस तरह कोडित की गईं:

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

इसके साथ:

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

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

निष्कर्ष? अस्तित्व को जांचने के लिए उपयोग किए जाने वाले हैंडल से छुटकारा पाने के कुछ अतुल्यकालिक पहलू हैं जो Microsoft से बात करने में सक्षम नहीं है। यह वैसा ही है जैसे यदि किसी कथन के अंदर एसिंक्रोनस विधि है, यदि कथन का उपयोग करने वाले कथन की तरह कार्य करता है।


0

आपको पुनरावृत्ति के लिए और अतिरिक्त विधि बनाने या फ़ोल्डर के अंदर फ़ाइलों को हटाने की आवश्यकता नहीं है। यह सब कॉल करके अपने आप हो जाता है

DirectoryInfo.Delete ();

विवरण यहाँ है

कुछ इस तरह से काफी अच्छा काम करता है:

  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
    }

विधि को हटाने के लिए चर के रूप में सही, उप फ़ाइलों को हटा देगा और फ़ाइलों के साथ उप फ़ोल्डर भी।


-2

उपरोक्त में से किसी भी उत्तर ने मेरे लिए काम नहीं किया। ऐसा प्रतीत होता है कि मेरे अपने ऐप का उपयोगDirectoryInfo लक्ष्य निर्देशिका पर कारण यह लॉक हो गया है।

मजबूरन कचरा संग्रह मुद्दे को हल करने के लिए दिखाई दिया, लेकिन अभी नहीं। जहाँ आवश्यकता हो वहाँ हटाने के कुछ प्रयास।

नोट करें Directory.Existsकि यह एक अपवाद के बाद गायब हो सकता है। मुझे नहीं पता कि मेरे लिए डिलीट करने में देरी क्यों हुई (Windows 7 SP1)

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

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

1
संयोग से -1 प्रोग्रामिंग। जब GC GC क्या वस्तु करता है? क्या यह किसी भी तरह से अच्छी सामान्य सलाह है? (मेरा मानना ​​है कि जब आप कहते हैं कि आपके पास एक समस्या थी और आपने इस कोड का उपयोग किया था और आपको लगता है कि आपको अब कोई समस्या नहीं है, लेकिन यह सिर्फ बात नहीं है)
रूबेन बार्टेलिंक

@RubenBartelink मैं सहमत हूं। यह हैक है। वूडू कोड जो कुछ करता है जब यह स्पष्ट नहीं है कि यह क्या हल कर रहा है या कैसे। मुझे उचित समाधान पसंद आएगा।
रिएक्टगुलर

1
मेरी समस्या यह है कि यह कुछ भी कहते हैं और stackoverflow.com/a/14933880/11635 से ऊपर अत्यधिक सट्टा है। अगर मैं कर सकता हूं, तो मैं दोहराव के लिए -1 और संयोग के लिए अटकल / प्रोग्रामिंग के लिए -1 दे रहा हूं। छिड़काव GC.Collectएक) सिर्फ बुरी सलाह और ख) योग्यता को शामिल करने के लिए बंद डेयर का पर्याप्त सामान्य सामान्य कारण नहीं है। बस दूसरों में से एक को चुनें और निर्दोष पाठकों के मन में अधिक भ्रम न
पालें

3
GC.WaitForPendingFinalizers () का उपयोग करें; GC.Collect () के बाद; यह उम्मीद के मुताबिक काम करेगा।
हेनर

यकीन नहीं है, अप्रशिक्षित, लेकिन शायद एक usingबयान के साथ कुछ करने के लिए बेहतर होगा , तो: 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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.