क्या किसी स्ट्रीमवर्टर को उसके बेसस्ट्रीम को बंद किए बिना बंद करने का कोई तरीका है?


117

मेरी जड़ समस्या यह है कि जब एक पर usingकॉल Disposeकिया जाता है StreamWriter, तो यह भी BaseStream(उसी समस्या के साथ Close) का निपटान करता है ।

मेरे पास इसके लिए वर्कअराउंड है, लेकिन जैसा कि आप देख सकते हैं, इसमें स्ट्रीम को कॉपी करना शामिल है। क्या धारा को कॉपी किए बिना ऐसा करने का कोई तरीका है?

इसका उद्देश्य एक स्ट्रिंग की सामग्री (मूल रूप से एक डेटाबेस से पढ़ा जाता है) को एक स्ट्रीम में प्राप्त करना है, इसलिए स्ट्रीम को तीसरे पक्ष के घटक द्वारा पढ़ा जा सकता है।
NB : मैं तीसरे पक्ष के घटक को बदल नहीं सकता।

public System.IO.Stream CreateStream(string value)
{
    var baseStream = new System.IO.MemoryStream();
    var baseCopy = new System.IO.MemoryStream();
    using (var writer = new System.IO.StreamWriter(baseStream, System.Text.Encoding.UTF8))
    {
        writer.Write(value);
        writer.Flush();
        baseStream.WriteTo(baseCopy); 
    }
    baseCopy.Seek(0, System.IO.SeekOrigin.Begin);
    return baseCopy;
}

इसके समान इस्तेमाल किया

public void Noddy()
{
    System.IO.Stream myStream = CreateStream("The contents of this string are unimportant");
    My3rdPartyComponent.ReadFromStream(myStream);
}

आदर्श रूप में मैं एक काल्पनिक पद्धति की तलाश में हूं BreakAssociationWithBaseStream, जैसे कि

public System.IO.Stream CreateStream_Alternate(string value)
{
    var baseStream = new System.IO.MemoryStream();
    using (var writer = new System.IO.StreamWriter(baseStream, System.Text.Encoding.UTF8))
    {
        writer.Write(value);
        writer.Flush();
        writer.BreakAssociationWithBaseStream();
    }
    return baseStream;
}

यह एक ऐसा ही सवाल है: stackoverflow.com/questions/2620851
जेन्स ग्रानलुंड

मैं एक WebRequest से एक धारा के साथ ऐसा कर रहा था, दिलचस्प बात यह है कि आप इसे बंद कर सकते हैं यदि एन्कोडिंग ASCII है, लेकिन UTB8 नहीं है। अजीब।
टोफुटिम

टोफुटिम, मेरे पास ASCII के रूप में कूटबद्ध किया गया था, और यह अभी भी अंतर्निहित धारा का निपटान करता है ..
जेरार्ड ओनिल

जवाबों:


121

यदि आप .NET फ्रेमवर्क 4.5 या बाद के संस्करण का उपयोग कर रहे हैं, तो एक स्ट्रीमवॉटर ओवरलोड है, जिसके उपयोग से आप लेखक के बंद होने पर आधार स्ट्रीम को खुला छोड़ देने के लिए कह सकते हैं

4.5 से पहले .NET फ्रेमवर्क के पहले संस्करणों में, यह माना जाता है StreamWriter कि यह स्ट्रीम का मालिक है। विकल्प:

  • निपटान मत करो StreamWriter; बस इसे फ्लश करें।
  • एक स्ट्रीम रैपर बनाएं जो कॉल को अनदेखा करता है Close/ Disposeलेकिन बाकी सब कुछ साथ में करता है। मैं MiscUtil में इसका कार्यान्वयन करता हूं , यदि आप इसे वहां से हड़पना चाहते हैं।

15
स्पष्ट रूप से 4.5 अधिभार एक रियायत नहीं सोचा गया था - अधिभार को बफर आकार की आवश्यकता होती है, जो 0 या शून्य नहीं हो सकता है। आंतरिक रूप से मुझे पता है कि 128 अक्षर न्यूनतम आकार है, इसलिए मैंने इसे केवल 1 पर सेट किया है। अन्यथा यह 'फीचर' मुझे खुश करता है।
जेरार्ड ओनील सेप

क्या उस leaveOpenपैरामीटर को सेट करने का कोई तरीका है StreamWriterजिसे बनाया गया था?
c00000fd

@ c00000fd: ऐसा नहीं है कि मुझे इसकी जानकारी नहीं है।
जॉन स्कीट

1
@ वायपेकाई: "यदि मैं एक उप विधि के लिए एक धारा पारित करता हूं और वह उप विधि स्ट्रीमव्रीटर बनाता है, तो यह उस उप विधि के निष्पादन के अंत में निपटाया जाएगा" नहीं, यह बस सच नहीं है। यह तभी निपटाया जाएगा जब उस Disposeपर कुछ कॉल करेगा। समाप्ति की विधि स्वचालित रूप से ऐसा नहीं करती है। बाद में इसे अंतिम रूप दिया जा सकता है अगर इसमें एक अंतिम रूप है, लेकिन यह एक ही बात नहीं है - और यह अभी भी स्पष्ट नहीं है कि आप किस खतरे का अनुमान लगा रहे हैं। अगर आपको लगता है कि यह StreamWriterकिसी विधि से वापस आना असुरक्षित है क्योंकि यह जीसी द्वारा स्वचालित रूप से निपटाया जा सकता है, तो यह सच नहीं है।
जॉन स्कीट

1
@ वायपेकाई: और आईआईआरसी के StreamWriterपास एक अंतिम रूप नहीं है - मैं इसकी उम्मीद नहीं करूंगा, ठीक इसी कारण से।
जॉन स्कीट

44

.NET 4.5 को नया तरीका मिला है!

http://msdn.microsoft.com/EN-US/library/gg712853(v=VS.110,d=hv.2).aspx

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

धन्यवाद दोस्त! यह नहीं पता था, और अगर कुछ भी जो मेरे लिए ठीक होने का एक उचित कारण होगा।
वेक्टोवॉक्स

22
शर्म की बात है कि कोई भी अधिभार नहीं है जिसे सेट करने के लिए बफरसाइज़ की आवश्यकता नहीं है। मैं वहां डिफ़ॉल्ट के साथ खुश हूं। मुझे इसे स्वयं पास करना है। दुनिया समाप्त नहीं हो जाती है।
एंडी मैकक्लोड सामान

3
डिफ़ॉल्ट bufferSizeहै 1024विवरण यहाँ हैं
एलेक्स क्लॉज़

35

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


2
@Marc, Flushअगर यह बफ़र्स डेटा के मामले में काम नहीं कर रहा है?
डारिन दिमित्रोव

3
ठीक है, लेकिन एक बार जब हम क्रिएटस्ट्रीम से बाहर निकलते हैं, तो स्ट्रीमवार्टियर संग्रहणीय है, तीसरे भाग के पाठक को जीसी के खिलाफ दौड़ के लिए मजबूर करता है, जो कि ऐसी स्थिति नहीं है जिसे मैं छोड़ना चाहता हूं। या मैं कुछ याद नहीं कर रहा हूं?
बाइनरी वॉरियर

9
@ BinaryWorrier: नहीं, कोई दौड़ की स्थिति नहीं है: StreamWriter में एक अंतिम रूप नहीं है (और वास्तव में नहीं होना चाहिए)।
जॉन स्कीट

10
@ बेसिनरी बैरियर: यदि आपके पास सीधे संसाधन हैं तो आपके पास केवल एक अंतिम उपकरण होना चाहिए । इस मामले में, StreamWriter को यह मान लेना चाहिए कि यदि आवश्यक हो तो स्ट्रीम स्वयं को साफ कर लेगी।
जॉन स्कीट

2
ऐसा लगता है कि स्ट्रीमराइटर की 'करीब' पद्धति भी धारा को बंद और निष्क्रिय कर देती है। तो एक को फ्लश करना चाहिए, लेकिन स्ट्रीमराइटर को बंद या डिस्पोज़ नहीं करना चाहिए, इसलिए यह स्ट्रीम को बंद नहीं करता है, जो स्ट्रीम को डिस्पोज़ करने के बराबर होगा। यहां एपीआई से बहुत अधिक "मदद" करें।
जेरार्ड ओनेइल

5

मेमोरी स्ट्रीम में एक ToArray गुण होता है जिसका उपयोग स्ट्रीम बंद होने पर भी किया जा सकता है। स्थिति संपत्ति की परवाह किए बिना, सरणी सामग्री को बाइट सरणी में लिखता है। आपके द्वारा लिखी गई स्ट्रीम के आधार पर आप एक नई स्ट्रीम बना सकते हैं।

public System.IO.Stream CreateStream(string value)
{
    var baseStream = new System.IO.MemoryStream();
    var baseCopy = new System.IO.MemoryStream();
    using (var writer = new System.IO.StreamWriter(baseStream, System.Text.Encoding.UTF8))
    {
        writer.Write(value);
        writer.Flush();
        baseStream.WriteTo(baseCopy); 
    }
    var returnStream = new System.IO.MemoryStream( baseCopy.ToArray());
    return returnStream;
}

क्या यह सही ढंग से सामग्री आकार में लौटे सरणी को सीमित करता है? क्योंकि Stream.Positionकर सकते हैं नहीं के बाद यह निपटारा है कहा जा।
Nyerguds

2

आपको StreamWriter का एक वंशज बनाने और इसकी डिस्पोज़ विधि को ओवरराइड करने की आवश्यकता है, हमेशा डिस्पोज़ करने वाले पैरामीटर को गलत तरीके से पारित करने से, यह स्ट्रीम लेखक को बंद करने के लिए मजबूर नहीं करेगा, स्ट्रीमविटर सिर्फ क्लोज़ विधि में डिस्पोज़ को कॉल करता है, इसलिए कोई ज़रूरत नहीं है इसे ओवरराइड करें (यदि आप चाहें तो सभी कंस्ट्रक्टरों को जोड़ सकते हैं, मेरे पास बस एक है):

public class NoCloseStreamWriter : StreamWriter
{
    public NoCloseStreamWriter(Stream stream, Encoding encoding)
        : base(stream, encoding)
    {
    }

    protected override void Dispose(bool disposing)
    {
        base.Dispose(false);
    }
}

3
मेरा मानना ​​है कि यह वह नहीं करता है जो आप सोचते हैं कि यह करता है। disposingध्वज का हिस्सा है पैटर्न । हमेशा आधार वर्ग की विधि से गुजरना मूल रूप से संकेत देता है कि इसे अंतिम रूप से कहा जा रहा है (जो ऐसा तब नहीं है जब आप स्पष्ट रूप से कहते हैं ), और इस प्रकार किसी भी प्रबंधित वस्तुओं का उपयोग नहीं करना चाहिए। यही कारण है कि यह आधार धारा का निपटान नहीं करेगा। हालाँकि, जिस तरह से आपने इसे हासिल किया है वह हैक है; यह बहुत आसान हो जाएगा बस पहली जगह में फोन नहीं है! IDisposablefalseDispose(bool)StreamWriterDispose()Dispose
stakx -

Thats Symantec वास्तव में, आप स्क्रैच से पूरी तरह से पुनर्लेखन के अलावा कुछ भी करते हैं, एक हैक होने जा रहा है। निश्चित रूप से, हालांकि, आप बस आधार नहीं कह सकते हैं। विपक्षी (झूठा) बिल्कुल भी नहीं कहेंगे, लेकिन कोई कार्यात्मक अंतर नहीं होगा, और मुझे अपने उदाहरण की स्पष्टता पसंद है। हालाँकि, इसे ध्यान में रखें, स्ट्रीमव्यूटर वर्ग का एक भविष्य का संस्करण, जब यह निपटान करता है, तो धारा को बंद करने से अधिक कर सकता है, इसलिए कॉलिंग डिस्पोजल (गलत) भविष्य के सबूतों को भी इसका सबूत देता है। लेकिन प्रत्येक उसके अपने के लिए।
एरोन मुर्गटारॉयड

2
ऐसा करने का एक और तरीका यह होगा कि आप अपना स्वयं का स्ट्रीम रैपर बनाएं जिसमें एक और स्ट्रीम शामिल हो जहां क्लोज विधि केवल अंतर्निहित स्ट्रीम को बंद करने के बजाय कुछ नहीं करता है, यह एक हैक से कम है लेकिन एक अधिक काम है।
आरोन मुर्गटारॉयड

कमाल समय: मैं बस के बारे में एक ही बात का सुझाव देना (डेकोरेटर वर्ग, संभवतः नामित था OwnedStream, कि ध्यान न दी Dispose(bool)और Close)।
stakx - अब

हाँ, ऊपर वाला कोड यह है कि मैं इसे एक त्वरित और गंदे तरीके के लिए कैसे करता हूं, लेकिन अगर मैं एक व्यावसायिक अनुप्रयोग या ऐसा कुछ बना रहा था, जो वास्तव में मेरे लिए मायने रखता था, तो मैं इसे सही ढंग से स्ट्रीम रैपर वर्ग का उपयोग करूँगा। व्यक्तिगत रूप से मुझे लगता है कि Microsoft ने यहाँ एक गलती की है, स्ट्रीमराइटर के पास अंतर्निहित स्ट्रीम को बंद करने के लिए बूलियन प्रॉपर्टी होनी चाहिए थी, लेकिन फिर मैं Microsoft पर काम नहीं करता, इसलिए वे वही करते हैं जो मुझे लगता है: D
हारून Murgatroyd
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.