2010-07-13 2 views
13

मेरे पास एक कक्षा है जो सक्रिय होने पर अस्थायी फ़ाइलों (Path.GetTempFileName()) का उपयोग करती है। मैं यह सुनिश्चित करना चाहता हूं कि मेरे प्रोग्राम बंद होने के बाद ये फ़ाइलें उपयोगकर्ता की हार्ड ड्राइव पर जगह न ले जाएं। अभी मेरी कक्षा में Close() विधि है जो जांचता है कि कक्षा द्वारा उपयोग की जाने वाली कोई भी अस्थायी फ़ाइलें अभी भी मौजूद हैं और उन्हें हटा देती हैं।अस्थायी फ़ाइलों को हटाने के लिए() या अंतिम रूप() का उपयोग करना चाहिए?

क्या इस कोड को निपटान() या अंतिम रूप() विधियों में रखने के लिए और अधिक समझदारी होगी?

+0

stragglers से सावधान रहें। यह संभव है कि सिस्टम किसी भी कारण से एक temp फ़ाइल लॉक करेगा और निपटान के दौरान आपका डिलीट विफल हो जाएगा। आपको अभी भी कुछ समय पर इन्हें हटाने की आवश्यकता होगी, कम से कम आपके फाइल सिस्टम पर ज़ोंबी का एक गुच्छा है। – diadem

उत्तर

39

बेहतर अभी तक FileOptions.DeleteOnClose के साथ फ़ाइल बनाना होगा। यह सुनिश्चित करेगा कि जब आपकी प्रक्रिया निकलती है (यहां तक ​​कि अशिष्ट गर्भपात के मामले में) ऑपरेटिंग सिस्टम जबरन फ़ाइल को हटा देता है। बेशक, जब भी आप इसके साथ काम करते हैं, तब भी आप फाइल को बंद/हटाना चाहेंगे, लेकिन यह सुनिश्चित करने के लिए कि आप फ़ाइलों को हमेशा के लिए बैठने की अनुमति नहीं देते हैं,

+4

+1 एक बहुत ही कम इस्तेमाल की जाने वाली सुविधा के लिए। –

+5

उदाहरण: 'का उपयोग कर (फ़ाइलस्ट्रीम एफएस = फ़ाइल। क्रेट (पथ। गेटटेम्फफाइलनाम(), Int16.MaxValue, FileOptions.DeleteOnClose)) // // temp फ़ाइल का उपयोग करें} // फ़ाइल हटा दी जाएगी –

0

बिल्कुल। इस तरह आप अपवादों के साथ सफाई सुनिश्चित कर सकते हैं।

+3

मान लीजिए कि आप सी # का उपयोग करते हैं, अपनी कक्षा को एक प्रयोग() कोड ब्लॉक में रखें। जब आपकी कक्षा का उदाहरण गुंजाइश (सामान्य वापसी या अपवाद) से बाहर हो जाता है, तो आपका निपटान() कॉल किया जाएगा। – GregC

+3

अंगूठे का नियम उन सभी वर्गों के लिए IDISposable लागू करना है जो ऑब्जेक्ट्स लागू करने वाली ऑब्जेक्ट के संदर्भ में हैं। इसके लिए एक FxCop नियम है। – GregC

0

संसाधनों को साफ करने के लिए आपको निश्चित रूप से Dispose का उपयोग करना चाहिए, लेकिन सुनिश्चित करें कि आप IDisposable इंटरफ़ेस को कार्यान्वित करें। आप Dispose नामक एक विधि नहीं जोड़ना चाहते हैं।

5

एक फ़ाइल एक अप्रबंधित संसाधन है, और आप अप्रबंधित संसाधनों को साफ करने के लिए IDISposable लागू करते हैं, जिन पर आपकी कक्षाएं निर्भर हैं।

मैंने समान कक्षाएं लागू की हैं, हालांकि उत्पादन कोड में कभी नहीं।

हालांकि, मैं इस बारे में आपकी सहजता को समझता हूं - आपके आवेदन के बाहर की फ़ाइलों के साथ उपयोगकर्ता इंटरैक्शन चीजों को पेंच कर सकता है और निपटान के दौरान समस्याएं पैदा कर सकता है। हालांकि, यह एक आवेदन द्वारा बनाई गई/हटाई गई किसी भी फ़ाइल के लिए समान है, भले ही यह किसी निपटान() विधि से संबंधित है या नहीं।

मुझे यह कहना होगा कि IDISposable लागू करना एक उचित विकल्प होगा।

1

एक अच्छा तरीका है Path.GetTempFileName पर एमएसडीएन प्रविष्टि पर डेविड एम। केन द्वारा सुझाया गया। उन्होंने कहा कि स्वचालित रूप से फ़ाइल को हटा देगा एक आवरण वर्ग IDisposable को लागू बनाता है:

public class TemporaryFile : IDisposable 
{ 
    private bool _isDisposed; 

    public bool Keep { get; set; } 
    public string Path { get; private set; } 

    public TemporaryFile() : this(false) 
    { 
    } 

    public TemporaryFile(bool shortLived) 
    { 
     this.Path = CreateTemporaryFile(shortLived); 
    } 

    ~TemporaryFile() 
    { 
     Dispose(false); 
    } 

    public void Dispose() 
    { 
     Dispose(false); 
     GC.SuppressFinalize(this); 
    } 

    protected virtual void Dispose(bool disposing) 
    { 
     if (!_isDisposed) 
     { 
      _isDisposed = true; 

      if (!this.Keep) 
      { 
       TryDelete(); 
      } 
     } 
    } 

    private void TryDelete() 
    { 
     try 
     { 
      File.Delete(this.Path); 
     } 
     catch (IOException) 
     { 
     } 
     catch (UnauthorizedAccessException) 
     { 
     } 
    } 

    public static string CreateTemporaryFile(bool shortLived) 
    { 
     string temporaryFile = System.IO.Path.GetTempFileName(); 

     if (shortLived) 
     { 
      // Set the temporary attribute, meaning the file will live 
      // in memory and will not be written to disk 
      // 
      File.SetAttributes(temporaryFile, 
       File.GetAttributes(temporaryFile) | FileAttributes.Temporary); 
     } 

     return temporaryFile; 
    } 
} 

का उपयोग करते हुए नया वर्ग के लिए आसान है, बस निम्न लिखें:

using (TemporaryFile temporaryFile = new TemporaryFile()) 
{ 
    // Use temporary file 
} 

यदि आप तय, एक अस्थायी फ़ाइल बनाने के बाद, कि आप इसे हटाए जाने से रोकना चाहते हैं, बस अस्थायी फ़ाइल सेट करें। संपत्ति को सही रखें:

using (TemporaryFile temporaryFile = new TemporaryFile()) 
{ 
    temporaryFile.Keep = true; 
} 
1

मैं हमेशा अपने वर्गों है कि अस्थायी फ़ाइलों IDisposable ओर इंगित करते हैं, और आम तौर पर एक finalizer कि मेरे निपटाने विधि वहाँ के रूप में अच्छी कॉल को लागू। ऐसा लगता है कि IDisposable MSDN page द्वारा सुझाया गया प्रतिमान है।

नीचे संबंधित कोड:

public void Dispose() 
{ 
    Dispose(true); 
    // This object will be cleaned up by the Dispose method. 
    // Therefore, you should call GC.SupressFinalize to 
    // take this object off the finalization queue 
    // and prevent finalization code for this object 
    // from executing a second time. 
    GC.SuppressFinalize(this); 
} 

// Dispose(bool disposing) executes in two distinct scenarios. 
// If disposing equals true, the method has been called directly 
// or indirectly by a user's code. Managed and unmanaged resources 
// can be disposed. 
// If disposing equals false, the method has been called by the 
// runtime from inside the finalizer and you should not reference 
// other objects. Only unmanaged resources can be disposed. 
private void Dispose(bool disposing) 
{ 
    // Check to see if Dispose has already been called. 
    if(!this.disposed) 
    { 
     // If disposing equals true, dispose all managed 
     // and unmanaged resources. 
     if(disposing) 
     { 
      // Dispose managed resources. 

     } 

     // Call the appropriate methods to clean up 
     // unmanaged resources here. 
     // If disposing is false, 
     // only the following code is executed. 


     // Note disposing has been done. 
     disposed = true; 

    } 
} 



// Use C# destructor syntax for finalization code. 
// This destructor will run only if the Dispose method 
// does not get called. 
// It gives your base class the opportunity to finalize. 
// Do not provide destructors in types derived from this class. 
~MyResource() 
{ 
    // Do not re-create Dispose clean-up code here. 
    // Calling Dispose(false) is optimal in terms of 
    // readability and maintainability. 
    Dispose(false); 
} 
+0

अंतिमकरण का उपयोग न करें। उनके बारे में जानें, लेकिन दूर रहें (जब तक आप अग्रिम प्रबंधित कोड सामग्री नहीं कर रहे हों)। https://ericlippert.com/2015/05/18/when-everything-you-now-is-wrong-part-one/ – PMBjornerud

8

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

http://msdn.microsoft.com/en-us/library/system.idisposable.aspx

ध्यान दें कि आप वास्तव में वास्तव में सावधान होने के लिए जब एक finalizer लेखन मिल गया है। जब finalizer चलाता है, अपने सामान्य मान्यताओं के कई गलत कर रहे हैं:

  • क्योंकि आप मुख्य थ्रेड पर नहीं रह रहे हैं वहाँ दौड़ की स्थिति या गतिरोध के लिए क्षमता के सभी प्रकार हैं, तो आप finalizer धागे पर कर रहे हैं।

  • नियमित कोड में, यदि आप किसी ऑब्जेक्ट के अंदर कोड चला रहे हैं तो आप जानते हैं कि ऑब्जेक्ट को संदर्भित करने वाली सभी चीजें जीवित हैं। फाइनल में, ऑब्जेक्ट को संदर्भित करने वाली सभी चीजें अभी अंतिम रूप दी गई हैं! मृत वस्तुओं के अंतिमकर्ता किसी भी क्रम में चला सकते हैं, जिसमें "बच्चे" वस्तुओं को "पैरेंट" ऑब्जेक्ट्स से पहले अंतिम रूप दिया जा रहा है।

  • नियमित कोड में, किसी स्थिर क्षेत्र में ऑब्जेक्ट का संदर्भ निर्दिष्ट करना पूरी तरह से समझदार हो सकता है। अंतिम रूप में, जो संदर्भ आप असाइन कर रहे हैं वह पहले से ही मृत वस्तु हो सकता है, और इसलिए असाइनमेंट एक मृत वस्तु को वापस जीवन में लाता है। (क्योंकि स्थैतिक क्षेत्रों द्वारा संदर्भित वस्तुओं को हमेशा जीवित रहते हैं।) यह है अजीब स्थिति में होना और कुछ भी सुखद नहीं होता है यदि आप करते हैं।

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

1

यदि आप अपनी अस्थायी फ़ाइलों का पुन: उपयोग करना चाहते हैं उदा। खुला \ Close \ read \ write \ etc खोलें, फिर उन्हें AppDomain अनलोड स्तर पर साफ़ करना उपयोगी हो सकता है।

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

तकनीक का एक मूल उदाहरण (ब्रेवटी के लिए हटाए गए अपवाद हैंडलिंग के साथ)। मैं इस तकनीक का उपयोग फाइल-आधारित यूनिट परीक्षणों में करता हूं जहां यह समझ में आता है और उपयोगी होता है।

public static class TempFileManager 
{ 
    private static readonly List<FileInfo> TempFiles = new List<FileInfo>(); 
    private static readonly object SyncObj = new object(); 

    static TempFileManager() 
    { 
     AppDomain.CurrentDomain.DomainUnload += CurrentDomainDomainUnload; 
    } 

    private static void CurrentDomainDomainUnload(object sender, EventArgs e) 
    { 
     TempFiles.FindAll(file => File.Exists(file.FullName)).ForEach(file => file.Delete()); 
    } 

    public static FileInfo CreateTempFile(bool autoDelete) 
    { 
     FileInfo tempFile = new FileInfo(Path.GetTempFileName()); 

     if (autoDelete) 
     { 
      lock (SyncObj) 
      { 
       TempFiles.Add(tempFile); 
      } 
     } 

     return tempFile; 
    } 
} 
संबंधित मुद्दे