System.IO.IOException: System.IO.Path.GetTempFileName () - रिज़ॉल्यूशन का उपयोग करते समय "फ़ाइल मौजूद है"?


84

जब भी उन्होंने मेरे उत्पाद का उपयोग करने की कोशिश की, मेरे ग्राहकों में से एक को अपवाद मिला। मुझे उस अपवाद का कॉलस्टैक प्राप्त हुआ जो हुआ था, जिसमें से शीर्ष है:

at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
   at System.IO.__Error.WinIOError()
   at System.IO.Path.GetTempFileName()
   at System.Windows.Input.Cursor.LoadFromStream(Stream cursorStream)
   at System.Windows.Input.Cursor..ctor(Stream cursorStream)

इसे देखते हुए, मैंने पाया कि इस अपवाद को कहते हुए बहुत सारे ब्लॉग पोस्ट फेंके गए जब% TEMP% फ़ोल्डर में 65535 से अधिक अस्थायी फ़ाइलें हैं, और इसका समाधान केवल पुरानी अस्थायी फ़ाइलों को साफ़ करना है। मैं ग्राहक को ऐसा करने के लिए कह सकता हूं, लेकिन यह केवल एक अस्थायी समाधान हो सकता है - क्या होगा अगर वे नियमित रूप से कुछ अन्य सॉफ़्टवेयर चला रहे हैं जो गेटटैम्पिलनेम को लगातार कॉल करते हैं, जो समस्या को बार-बार हल करेगा?

मैं बस प्रोग्राम को% TEMP% फ़ोल्डर से साफ़ नहीं कर सकता, क्योंकि यह किसी और चीज़ को नुकसान पहुंचा सकता है, और मैं GetTempFileName (और इसके बजाय अपने खुद के अस्थायी फ़ोल्डर का उपयोग करके) को कॉल करने से नहीं बच सकता क्योंकि यह मुझे नहीं बल्कि WPF कोड कह रहा है।

क्या इसका कोई स्थायी समाधान है?

अद्यतन : मैंने पुष्टि की है कि लॉग फ़ाइल के साथ% TEMP% फ़ोल्डर ओवरफ़्लो होने की समस्या मेरे अपने कोड के कारण नहीं है, और ग्राहक की मशीन पर कुछ अन्य तृतीय पक्ष एप्लिकेशन के कारण होना चाहिए। मैंने इसके क्रियान्वयन पर भी ध्यान दिया Cursor.LoadFromStreamऔर यह निश्चित रूप से गलती पर नहीं है - यह एक अस्थायी फ़ाइल उत्पन्न करता है, लेकिन फिर इसे finallyब्लॉक में हटा देता है ।


3
आप अपना खुद का "Temp" फ़ोल्डर बना सकते हैं, जो डिलीट हो जाता है (एप्लिकेशन डेटा में) "लेकिन संभवतः सभी संदर्भों को बदलने के लिए एक बैलेच होगा, अच्छा सवाल
— Sayse

यह सवाल WPF, हटाए गए टैग से संबंधित नहीं है। इसके अलावा, सिर्फ कोड को ठीक क्यों नहीं किया जाता है, जो बिना विलोपन के इतनी सारी अस्थायी फाइलें तैयार करता है?
— डेनिस

1
@ लेकिन मैं ऐसा नहीं कर सकता क्योंकि यह WPF की Cursor.LoadFromStreamअस्थायी फ़ाइल है। @ डेनिस यह डब्ल्यूपीएफ की Cursor.LoadFromStreamकक्षा से संबंधित है । आपत्तिजनक कोड जो बिना विलोपन के इतने सारे अस्थायी फाइल का उत्पादन करता है, वह मेरा खुद का भी नहीं हो सकता है, और मुझे अभी भी अपवाद को संबोधित करने की आवश्यकता है।
— ओमर रविव

क्या आप पता लगा सकते हैं कि कौन सी एप्लीकेशन इन सभी अस्थायी फाइलों को पीछे छोड़ रही है? क्या यह आपका आवेदन है? यदि WPF इन अस्थायी फ़ाइलों को बना रहा है, तो क्या आपने पुष्टि की है कि यह उन्हें हटा रहा है जब उन्हें अब आवश्यकता नहीं है?
— आशिगोर

2
@OmerRaviv मुझे लगता है कि आपका एकमात्र विकल्प IOE को आज़माना / पकड़ना है, और उपयोगकर्ता से पूछें कि क्या वे चाहते हैं कि आप अस्थायी फ़ाइलों को हटा दें और फिर से प्रयास करें
— Sayse

जवाबों:


15

जैसा कि मैंने अपनी पिछली टिप्पणी में उल्लेख किया है, मुझे लगता है कि ऐसा करने का आपका एकमात्र सुरक्षित तरीका उपयोगकर्ता से पूछना है कि क्या वे चाहते हैं कि आप फ़ाइलों को हटा दें और फिर से प्रयास करें। यह जरूरी है कि आप उपयोगकर्ताओं को इस में इनपुट दें, यह इस तरह से अपने जोखिम पर है। मेरे सिर में इसके समान कुछ।

public Stream GetStream(Stream cursorStream)
{
    try
    {
       //getting stream
    }
    catch(IOE)
    {
        MessageBox.Show(this, "Unable to get stream, your temporary
                              folder may be full, do you want to try deleting 
                                some and try again?");
         if(yes)
         try
         {
             //delete and try again
             return GetStream(cursorStream);
         }
         catch(IOE)
          {
                //no luck
           }
          else
              return null;
    }

}

सुनिश्चित करने के लिए एक वैकल्पिक जाँच हो सकती है,

Directory.EnumerateFiles(Path.GetTempPath(), "*", SearchOption.TopLevelOnly)
  .Count() == ushort.MaxValue;

2
जैसा कि आपने सुझाया है मैं एक कोशिश / कैच के साथ जा रहा हूँ। आपके द्वारा सुझाया गया बूलियन परीक्षण वास्तव में गलत है - यह संभावना है कि% TEMP% फ़ोल्डर में अन्य फाइलें हैं, इसके अलावा "tmpXXXX.tmp" प्रारूप में जो GetTempFileName () का उपयोग करता है, इसलिए वास्तव में कोई समस्या नहीं होने पर आपका परीक्षण वापस आ सकता है और जब कोई समस्या हो तो गलत है।
— ओमेर रविवि 21:13

परीक्षण एक अस्थायी फ़ोल्डर में सभी फ़ाइलों को खोजने के लिए डिज़ाइन किया गया था (यद्यपि मैं मानता हूं कि यह सही अस्थायी फ़ोल्डर नहीं हो सकता है) और देखता है कि क्या यह 65535 के बराबर है, "*"सभी फ़ाइलों को ढूँढेगा (भले ही उनके पास कोई एक्सटेंशन हो या नहीं) आशा करता है कि आपकी मदद करेगा
— सईग

आप एक दिन से भी पुरानी सभी फ़ाइलों को हटा सकते हैं। एक दिन से पुरानी अस्थायी फ़ाइल किसी अन्य एप्लिकेशन द्वारा उपयोग में नहीं होने की संभावना नहीं है।
— जेटी टेलर

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

36

अगर उत्पादन के माहौल पर आपके साथ ऐसा हो रहा है या किसी ऐसे ऐप के साथ जिसे आप बदल नहीं सकते हैं, तो त्वरित समाधान Temp फ़ोल्डर को खाली करना है।

उस उपयोगकर्ता पर निर्भर करता है जो एप्लिकेशन चला रहा है या तो आपको चाहिए

  • खाली C:\Windows\Temp(IIS या सेवाओं के तहत चल रहा है) के लिएLocalSystem खाते के लिए)
  • या %temp%उपयोगकर्ताओं के लिए स्थानीय रूप से लॉग ऑन (जो मेरे लिए है C:\Users\MyUserName\AppData\Local\Temp)।

दूसरी तरफ, यदि आपका अपना कोड इसे फेंक रहा है, और आप इसे फिर से होने से रोकना चाहते हैं:

  1. System.IO.Path.GetTempFileName () का उपयोग न करें!

GetTempFileName()दो दशक पुरानी Win32 Api का रैपर है । यह फ़ाइल नाम उत्पन्न करता है जो बहुत आसानी से टकराएगा। यह फ़ाइल सिस्टम पर भारी लूपिंग द्वारा उन टकरावों को दरकिनार करता है, जो पहले से मौजूद लोगों के "%temp%\tmp0000.tmp"लिए संभव फ़ाइल नामों को पुनरावृत्त करता है "tmpFFFF.tmp"और छोड़ देता है। यह एक I / O गहन, धीमा और स्पष्ट रूप से भयानक एल्गोरिथ्म है। इसके अलावा केवल 4 हेक्स वर्णों का उपयोग करना विफल होने से पहले 65536 फ़ाइलों की कृत्रिम सीमा बनाता है।

विकल्प फ़ाइल नाम उत्पन्न करने के लिए है जो टकराएगा नहीं। उदाहरण के लिए, GUID'sतर्क का पुन : उपयोग करने देता है: 32 हेक्स अंक लगभग कभी नहीं टकराएंगे।

private string GetTempFileName()
{
    return Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
}
// Sample: c:\Windows\Temp\2e38fe87-f6bb-4b0d-90b3-2d07016324c1

यह 65k से 4k लाखों फ़ाइलों तक की सीमा का विस्तार करता है (सैद्धांतिक रूप से) ... बेशक, लीक होने वाली 65k फाइलें पहले से ही भयानक हैं, इसलिए ...

  1. अस्थायी फ़ाइलों को लीक न करें!

सभी खुश और दुखी रास्तों (जैसे अप्रत्याशित अपवाद) के लिए अपने ऐप को दोबारा जांचें। सुनिश्चित करें कि यह सही ढंग से प्रत्येक FileStream को निपटाने और अंत में ब्लॉकों में अस्थायी फ़ाइलों को हटाने है।

  1. अस्थायी फ़ोल्डर साफ़ करें

इसे अभी साफ करें, और सिस्टम प्रशासक को समय-समय पर इसे साफ करने के लिए शिक्षित करें, क्योंकि आप जंगली में हर ऐप पर भरोसा नहीं कर सकते हैं। अपने स्वयं के सर्वर पर मैं इस कार्य को स्वचालित रूप से करूँगा:

  • वैश्विक Windows \ Temp के लिए

schtasks /Create /TR "cmd /c call DEL /F /S /Q %^TEMP%" /TN "Delete Global Temp Files" /sc WEEKLY /ST 12:00 /ru system

  • वर्तमान उपयोगकर्ता के लिए:

schtasks /Create /TR "cmd /c call DEL /F /S /Q %^TEMP%" /TN "Delete %username% Temp Files" /sc WEEKLY /ST 12:00


5

यहाँ कोड का उपयोग मैंने अंत में किया है, और किसी भी कॉल के आने से पहले अपने ऐप के इनिशियलाइज़ेशन कोड-पाथ में जल्दी डाल Cursor.LoadFromStreamसकता हूँ:

    private void WarnUserIfTempFolderFull()
    {
        string tempFile = null;
        try
        {
            tempFile = Path.GetTempFileName();
        }
        catch (IOException e)
        {
            string problem = "The Temporary Folder is full.";

            string message = "{ProductName} has detected that the Windows Temporary Folder is full. \n" + 
                             "This may prevent the {ProductName} from functioning correctly.\n" + 
                             "Please delete old files in your temporary folder (%TEMP%) and try again.";

            Logger.Warn(problem);

            MessageBox.Show(message, caption: problem);
        }
        finally
        {
            if (tempFile != null) File.Delete(tempFile);
        }
    }

2

समाधान:

  1. सर्वाधिक उपयुक्त। पता लगाएँ कि कौन सी एप्लिकेशन बहुत सारी अस्थायी फ़ाइलों का उत्पादन कर रही है और उन्हें हटा नहीं रही है। जैसी उपयोगिताएँ Process monitorआपको मदद करनी चाहिए। फिर या तो आवेदन को ठीक करें या इसे फेंक दें। और हाँ, यह आपका आवेदन हो सकता है। इसलिए मैं आपको बुराई के स्रोत का पता लगाने की सलाह दूंगा।
  2. सबसे आसान। अपनी अस्थायी निर्देशिका का उपयोग करें। यदि आपके कोड से फ़ाइलें बनाई जा रही हैं तो यह मदद नहीं करेगा।
  3. सबसे बदसूरत। अपने आवेदन से अस्थायी निर्देशिका को साफ़ करें। आप परिणामों के बारे में बिल्कुल सही हैं - आप किसी अन्य एप्लिकेशन को तोड़ सकते हैं।

अपने खुद के अस्थायी निर्देशिका का उपयोग करना जरूरी नहीं कि एक समाधान है। मैं एक tempfilename उत्पन्न करने के लिए एपीआई का उपयोग करता हूं, लेकिन इसे अपनी खुद की निर्देशिका में लिखता हूं। दुर्भाग्य से यह भी विफल रहता है।
— जॉर्ज मौएर

2
// one more implementation
string GetTempFileName()
{
    return Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
}

1

जैसा कि Sayse ने सुझाव दिया है, जब आपका ऐप लॉन्च होता है, तो आप% TEMP% पर्यावरण चर सेट करने का प्रयास कर सकते हैं।

Environment.SetEnvironmentVariable("TEMP", "<dir>");

यह एक बहुत अच्छा विचार है, लेकिन दुर्भाग्य से मेरा ऐप एक विजुअल स्टूडियो एक्सटेंशन है जिसे शांतिपूर्वक अन्य एक्सटेंशन के साथ सह-अस्तित्व में होना चाहिए, और मुझे डर है कि यह किसी भी तरह अनजाने में अन्य एक्सटेंशन के व्यवहार को नुकसान पहुंचा सकता है।
— ओमेर रविवि

यह समाधान मदद नहीं करेगा यदि यह उसका अपना कार्यक्रम है जो इन सभी फ़ाइलों को पीछे छोड़ रहा है। नई निर्देशिका बस भर जाएगी और यह एक फ़ोल्डर से फ़ाइलों को मनमाने ढंग से हटाने के लिए बुरा है जब आपको पता नहीं होता है कि वे आपके आवेदन के लिए एक फ़ोल्डर विशिष्ट होने पर भी क्या हैं।
— आशिगोर

@ अशिगोर हां, जाहिर है कि यह एक बग को ठीक नहीं करेगा जो उसने बनाया है। विशेष रूप से संदर्भित what if they are regularly running some other piece of software that makes frequent calls to GetTempFileName।
— एड चैपल

@OmerRaviv यह जानकारी सहायक है। वास्तव में यह इस परिदृश्य में काम नहीं करेगा।
— एड चैपल

1
क्षमा करें @EdChapel, SO ने मेरे वोट को लॉक कर दिया है, मैं इसे हटा नहीं सकता जब तक कि जवाब संपादित नहीं किया जाता।
— गेरार्डो ग्रिग्नोली

1

किसी और के लिए जिसने इस समस्या का अनुभव किया है और किसी भी अतिप्रवाह अस्थायी फ़ोल्डर को नहीं ढूंढ सकता है - "C: / Windows / Temp" -folder की जाँच करें। इस फोल्डर को साफ करने से मेरी समस्याएं हल हो गईं।

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