क्या स्ट्रीमरैपर्स को निपटाने से स्ट्रीम बंद हो जाती है?


166

मैं लिखने के तरीकों के लिए एक धारा भेज रहा हूं, और उन तरीकों में मैं एक द्विआधारी पाठक / लेखिका का उपयोग कर रहा हूं। जब पाठक / लेखक का निस्तारण हो जाता है, या तो usingया जब उसे संदर्भित नहीं किया जाता है, तो क्या धारा भी बंद हो जाती है ??

मैं एक बाइनरीरीडर / राइटर भेजूंगा, लेकिन मैं एक स्ट्रीमराइडर का भी उपयोग कर रहा हूं (हो सकता है कि मुझे इसके चारों ओर जाना चाहिए। मैं केवल गेटलाइन और रीडलाइन के लिए इसका उपयोग कर रहा हूं)। यदि लेखक / पाठक बंद हो जाता है तो यह स्ट्रीम को बंद कर देता है तो यह काफी तकलीफदेह होता है।

जवाबों:


204

हाँ, StreamReader, StreamWriter, BinaryReaderऔर BinaryWriterसभी पास / उनके अंतर्निहित धाराओं निपटाने जब आप कॉल Disposeउन पर। यदि पाठक / लेखक केवल कचरा एकत्र नहीं करते हैं, तो वे धारा का निपटान नहीं करते हैं - आपको हमेशा एक usingबयान के साथ पाठक / लेखक का निपटान करना चाहिए । (वास्तव में, इनमें से किसी भी वर्ग के पास अंतिम रूप नहीं है, और न ही उनके पास होना चाहिए।)

व्यक्तिगत रूप से मैं स्ट्रीम के लिए भी एक स्टेटमेंट का उपयोग करना पसंद करता हूं। आप usingब्रेसिज़ के बिना काफी करीने से बयान कर सकते हैं :

using (Stream stream = ...)
using (StreamReader reader = new StreamReader(stream, Encoding.Whatever))
{
}

हालांकि usingधारा के लिए बयान कुछ हद तक बेमानी है (जब तक कि StreamReaderनिर्माता एक अपवाद नहीं फेंकता) मैं इसे सबसे अच्छा अभ्यास मानता हूं, अगर आप इससे छुटकारा पा लेते हैं StreamReaderऔर बाद में सीधे स्ट्रीम का उपयोग करते हैं, तो आपके पास पहले से ही सही निपटान होगा अर्थ विज्ञान।


2
ओह अच्छा, यह केवल तब होता है जब कॉलिंग डिस्पोज़ की जाती है, न कि जब अंतिम रूप से अंतिम रूप देने की।
नेफजेन

1
@ नेफ़जन: ऐसा इसलिए है क्योंकि आपकी वस्तुओं को अंतिम रूप देने के लिए कोई गारंटी नहीं है। यदि स्ट्रीमराइडर और अंतर्निहित स्ट्रीम दोनों ही अंतिम रूप देने के योग्य हैं, तो GC पहले स्ट्रीम को अंतिम रूप दे सकता है - फिर स्ट्रीमराइडर में स्ट्रीम का संदर्भ नहीं होगा। इस कारण से, आप केवल अंतिम रूप के अंदर अप्रबंधित संसाधनों को जारी कर सकते हैं (उदाहरण के लिए, एक FileStream अपने विंडोज़ फ़ाइल हैंडल को अपने अंतिम रूप में बंद कर देता है)। ओह, और निश्चित रूप से, यदि आप कभी भी निपटान नहीं करते हैं, तो धारा को अंततः एकत्र किया जाएगा (और फ़ाइल बंद)। यह एक धारा को समाप्त नहीं करने के लिए सिर्फ एक बहुत बुरा अभ्यास है।
JMarsch

13
यह नेस्टिंग वीएस कोड विश्लेषक को शिकायत करने का कारण बनता है: CA2202 : Microsoft.Usage : Object 'stream' can be disposed more than once in method '...'. To avoid generating a System.ObjectDisposedException you should not call Dispose more than one time on an object.क्या इसे केवल अनदेखा किया जाना चाहिए? मुझे अब तक कोई अपवाद नहीं मिला ...
HB

15
@ एचबी: इस मामले में इसे अनदेखा करना सुरक्षित है। या आप केवल कंस्ट्रक्टर कॉल में स्ट्रीम बना सकते हैं StreamReader। चेतावनी मुझे फर्जी लगती है, यह देखते हुए कि IDisposable.Disposeस्पष्ट रूप से राज्य के लिए डॉक्स : "यदि किसी ऑब्जेक्ट के डिस्पोज़ विधि को एक से अधिक बार कॉल किया जाता है, तो ऑब्जेक्ट को पहले एक के बाद सभी कॉल को अनदेखा करना चाहिए। ऑब्जेक्ट को उसके डिस्पोज़ विधि से अपवाद नहीं फेंकना चाहिए। कई बार फोन किया। "
जॉन स्कीट

5
@JonSkeet: वास्तव में इसके लिए एक पेज है , आप सही थे, यह फर्जी है :)
HB

45

यह एक पुराना है, लेकिन मैं आज कुछ ऐसा ही करना चाहता था और पाया कि चीजें बदल गई हैं। 4.5 के बाद से, वहाँ एक leaveOpenतर्क है:

public StreamReader( Stream stream, Encoding encoding, bool detectEncodingFromByteOrderMarks, int bufferSize, bool leaveOpen )

एकमात्र समस्या यह है कि यह पूरी तरह से स्पष्ट नहीं है कि अन्य मापदंडों के लिए क्या निर्धारित किया जाए। यहाँ कुछ मदद है:

StreamReader कन्स्ट्रक्टर (स्ट्रीम) के लिए msdn पेज से :

यह कंस्ट्रक्टर UTF8Encoding के लिए एन्कोडिंग को प्रारंभ करता है, स्ट्रीम पैरामीटर का उपयोग करके बेसस्ट्रीम प्रॉपर्टी और 1024 बाइट्स के लिए आंतरिक बफर आकार।

वह बस detectEncodingFromByteOrderMarksजो कोड कोड को देखकर छोड़ देता हैtrue

public StreamReader(Stream stream)
        : this(stream, true) {
}

public StreamReader(Stream stream, bool detectEncodingFromByteOrderMarks)
        : this(stream, Encoding.UTF8, detectEncodingFromByteOrderMarks, DefaultBufferSize) {
}

यह अच्छा होगा यदि उन डिफॉल्ट्स में से कुछ को उजागर किया गया था या यदि तर्क वैकल्पिक थे ताकि हम केवल उन लोगों को निर्दिष्ट कर सकें जो हम चाहते हैं।


बहुत अच्छी जानकारी! इस नए पैरामीटर के बारे में कभी नहीं सुना और यह वास्तव में बहुत मायने रखता है।
जुलैलेगन

3
मेरे जैसे आलसी लोगों के लिए, धारा को खुला छोड़ने का संक्षिप्त उत्तर इस प्रकार होगा:using (var streamReader = new StreamReader(myStream, Encoding.UTF8, true, 1024, true))
बीवर

29

हाँ यह करता है। आप इसे रिफ्लेक्टर के कार्यान्वयन को देखकर सत्यापित कर सकते हैं।

protected override void Dispose(bool disposing)
{
    try
    {
        if ((this.Closable && disposing) && (this.stream != null))
        {
            this.stream.Close();
        }
    }
    finally
    {
        if (this.Closable && (this.stream != null))
        {    
            this.stream = null;    
            this.encoding = null;
            this.decoder = null;
            this.byteBuffer = null;
            this.charBuffer = null;
            this.charPos = 0;
            this.charLen = 0;
            base.Dispose(disposing);
        }
    }
}

13

छह साल देर से लेकिन शायद यह किसी की मदद कर सकता है।

जब यह निपटाया जाता है तो स्ट्रीमराइडर कनेक्शन बंद कर देता है। हालाँकि, StreamReader / StreamWriter के साथ "(स्ट्रीम स्ट्रीम = ...) {...}" का उपयोग करके स्ट्रीम को दो बार निपटाया जा सकता है: (1) जब स्ट्रीमराइडर ऑब्जेक्ट का निपटान किया जाता है (2) और जब स्ट्रीम ब्लॉक का उपयोग करता है बंद कर देता है। यह वी। एस। कोड विश्लेषण चलाते समय CA2202 चेतावनी के परिणामस्वरूप होता है।

CA2202 पेज से सीधे लिया गया एक अन्य समाधान, एक कोशिश / अंत में ब्लॉक का उपयोग करना है। सही ढंग से सेटअप करें, यह केवल एक बार कनेक्शन बंद कर देगा।

CA2202 के निचले भाग के पास , Microsoft निम्नलिखित का उपयोग करने की अनुशंसा करता है:

Stream stream = null;
try
{
    stream = new FileStream("file.txt", FileMode.OpenOrCreate);
    using (StreamWriter writer = new StreamWriter(stream))
    {
        stream = null;
        // Use the writer object...
    }
}
finally
{
    if(stream != null)
        stream.Dispose();
}

के बजाय...

// Generates a CA2202 warning
using (Stream stream = new FileStream("file.txt", FileMode.Open))
using (XmlReader reader = new XmlReader (stream))
{
    // Use the reader object...
}

2
चेतावनी को स्वीकृत उत्तर की टिप्पणियों में भी चर्चा की गई है। जॉन स्कीट वहाँ कुछ सलाह प्रदान करता है।
Marcin

इसके अलावा, इस बात का ध्यान रखें कि उपयोग करने वाला कथन वास्तव में संकलक द्वारा एक कोशिश-अंत में ब्लॉक में परिवर्तित हो जाता है।
जेसन केली

2

हाँ। कॉलिंग डिसपोज़ () ऑन एंड आईडीसॉफ़ेरियल (जो "करता है") को अपने सभी संसाधनों को साफ़ करना चाहिए। इसमें धाराएँ शामिल हैं और उनकी फ़ाइल विवरणकों को बंद करना है।

यदि, आपके मामले में, आप इसे अन्य तरीकों से पारित करना चाहते हैं, तो आपको यह सुनिश्चित करने की आवश्यकता है कि वे विधियां उनके पढ़ने / लिखने का उपयोग एक ब्लॉक में नहीं करते हैं।


1

इसे ठीक करने का एक आसान तरीका यदि आपको आवश्यक है तो स्ट्रीमराइटर कक्षाओं को निपटाने की विधि को ओवरराइड करना है। यह करने के लिए कोड के लिए मेरी पोस्ट यहाँ देखें:

करता है। एक स्ट्रीमवॉटर को चुनने से अंतर्निहित स्ट्रीम बंद हो जाती है?


-2

"कीवर्ड" का उपयोग करके या स्पष्ट रूप से निपटान करके धारा का निपटान किया जाता है

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