2008-11-07 28 views
35

को डिकंप्रेस नहीं करेगा। मुझे .net में छवियों को संपीड़ित करने के तरीके की आवश्यकता थी, इसलिए मैंने .NET GZipStream क्लास (या DeflateStream) का उपयोग करने में देखा। हालांकि मुझे पता चला कि डिकंप्रेशन हमेशा सफल नहीं होता था, कभी-कभी छवियों को ठीक से डिकंप्रेस कर दिया जाएगा और दूसरी बार मुझे एक जीडीआई + त्रुटि मिलेगी जो कुछ दूषित हो गया है।GZipStream और DeflateStream सभी बाइट्स

इस मुद्दे की जांच करने के बाद मैंने पाया कि डिकंप्रेशन इसे संकुचित सभी बाइट्स वापस नहीं दे रहा था। तो अगर मैंने 2257974 बाइट्स को संपीड़ित किया तो मैं कभी-कभी केवल 2257870 बाइट्स (वास्तविक संख्या) वापस प्राप्त करूंगा।

सबसे मजेदार बात यह है कि कभी-कभी यह काम करेगा। इसलिए मैंने इस छोटी टेस्ट विधि को बनाया जो केवल 10 बाइट्स को संपीड़ित करता है और अब मुझे कुछ भी वापस नहीं मिलता है।

मैंने इसे संपीड़न कक्षाओं GZipStream और DeflateStream दोनों के साथ करने की कोशिश की और मैंने संभावित त्रुटियों के लिए अपना कोड दोहराया। मैंने स्ट्रीम को 0 पर स्थानांतरित करने और सभी धाराओं को फ़्लश करने की कोशिश की लेकिन बिना किसी किस्मत के। आप सभी डेटा आप सेक करना चाहते हैं जोड़ने के बाद Close()ZipStream की जरूरत

public static void TestCompression() 
    { 
     byte[] test = new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 

     byte[] result = Decompress(Compress(test)); 

     // This will fail, result.Length is 0 
     Debug.Assert(result.Length == test.Length); 
    } 

    public static byte[] Compress(byte[] data) 
    { 
     var compressedStream = new MemoryStream(); 
     var zipStream = new GZipStream(compressedStream, CompressionMode.Compress); 
     zipStream.Write(data, 0, data.Length); 
     return compressedStream.ToArray(); 
    } 

    public static byte[] Decompress(byte[] data) 
    { 
     var compressedStream = new MemoryStream(data); 
     var zipStream = new GZipStream(compressedStream, CompressionMode.Decompress); 
     var resultStream = new MemoryStream(); 

     var buffer = new byte[4096]; 
     int read; 

     while ((read = zipStream.Read(buffer, 0, buffer.Length)) > 0) { 
      resultStream.Write(buffer, 0, read); 
     } 

     return resultStream.ToArray(); 
    } 
+0

अपनी टिप्पणी दो - यह विभिन्न स्तरों पर बफर के लिए नीचे आता है; अगर वे सभी खाली नहीं हैं (सही क्रम में) तो आपको सभी डेटा नहीं मिलते हैं। –

+0

नोट, उदाहरण के लिए, मैंने मेमोरीस्ट्रीम पर बंद() को कॉल करने से परेशान नहीं किया - इसलिए मैं आंशिक रूप से सहमत हूं ;-p –

+0

मैं इस पर भी एक अपडेट जोड़ूंगा .... –

उत्तर

48

;:

यहाँ मेरी कोड है यह आंतरिक रूप से अनचाहे बाइट्स का एक बफर बरकरार रखता है (भले ही आप Flush()) जिसे लिखा जाना चाहिए।

आम तौर पर, Stream, IDisposable है, इसलिए आप भी using होना चाहिए प्रत्येक ... (हाँ, मुझे पता है कि MemoryStream किसी भी डेटा खोने के लिए नहीं जा रहा है, लेकिन अगर आप इस आदत में नहीं मिलता है, यह आपको Stream एस के साथ काटता है)।

public static byte[] Compress(byte[] data) 
{ 
    using (var compressedStream = new MemoryStream()) 
    using (var zipStream = new GZipStream(compressedStream, CompressionMode.Compress)) 
    { 
     zipStream.Write(data, 0, data.Length); 
     zipStream.Close(); 
     return compressedStream.ToArray(); 
    } 
} 

public static byte[] Decompress(byte[] data) 
{ 
    using(var compressedStream = new MemoryStream(data)) 
    using(var zipStream = new GZipStream(compressedStream, CompressionMode.Decompress)) 
    using (var resultStream = new MemoryStream()) 
    { ... } 
} 

[संपादित करें: अद्यतन फिर से टिप्पणी] पुन MemoryStream नहीं using तरह बातें - यह हमेशा एक मजेदार एक है, बाड़ के दोनों तरफ वोट के बहुत सारे के साथ: लेकिन ultimatey ...

(उदारवादी - हम सभी को जवाब पता है ...) MemoryStream कैसे लागू किया गया है? क्या यह एक बाइट [] है (.NET के स्वामित्व में)? क्या यह एक स्मृति-मैप की गई फ़ाइल है (ओएस के स्वामित्व में)?

कारण आप using नहीं हैं क्योंकि आप आंतरिक कार्यान्वयन विवरणों के ज्ञान को बता रहे हैं कि आप सार्वजनिक एपीआई के खिलाफ कैसे कोड करते हैं - यानी आपने बस encapsulation के नियम तोड़ दिए। सार्वजनिक एपीआई कहता है: मैं IDisposable हूं; आप मुझे जित लिये; इसलिए, जब आप के माध्यम से होते हैं तो यह Dispose() पर आपका काम है।

+0

वाह, यह एक आकर्षण की तरह काम किया। यह दिलचस्प है क्योंकि मुझे नहीं लगता था कि आंतरिक मेमोरी के लिए बंद() आवश्यक है क्योंकि इसमें कोई विंडोज संसाधन शामिल नहीं है (यह उपयोग ब्लॉक के लिए भी जाता है - यह उनके बिना केवल क्लीनर था) –

+0

बंद() मुक्त होने के बारे में नहीं है यहां एक विंडोज संसाधन। GZip को डेटा के अंत में एक पाद लेख की आवश्यकता होती है, और बंद() GZipStream को बताता है कि आपने डेटा लिखना समाप्त कर दिया है और इसे पाद लेख लिखना चाहिए। – stevemegson

+0

आप कार्यान्वयन विवरण देने के बारे में सही हो सकते हैं कि मैं सही कोड कैसे परिभाषित करता हूं। लेकिन हाल ही में माइक्रोसॉफ्ट बहुत से निपटान पैटर्न (यहां तक ​​कि किसी भी डिस्पोजेबल ऑब्जेक्ट्स पर) को लागू नहीं कर रहा है –

3

इसके अलावा - System.IO.Compression में DeflateStream को ध्यान में रखें, सबसे कुशल डिफ्लेट एल्गोरिदम लागू नहीं करता है। यदि आप चाहें, तो बीसीएल जीजेपस्ट्रीम और डिफ्लेटस्ट्रीम का एक विकल्प है; इसे ज़्लिब कोड के आधार पर पूरी तरह से प्रबंधित लाइब्रेरी में कार्यान्वित किया जाता है, जो इस संबंध में अंतर्निहित {Deflate, GZip} स्ट्रीम से बेहतर प्रदर्शन करता है। [लेकिन आपको अभी भी पूर्ण बायस्ट्रीम प्राप्त करने के लिए स्ट्रीम को बंद करने की आवश्यकता है। ]

इन धारा वर्गों को डॉटनेट जैलीब असेंबली में भेज दिया गया है, जो http://DotNetZip.codeplex.com/ पर डॉटनेटेट वितरण में उपलब्ध है।

+1

आप प्रसन्न होंगे यह सुनकर कि .NET 4.5 ने अब बीसीएल में ज़्लिब एल्गोरिदम में बुना है (मौजूदा संपीड़ित डेटा के लिए पिछड़ा संगतता के साथ)। अधिक जानकारी के लिए यहां देखें: http://msdn.microsoft.com/en-us/magazine/jj133817.aspx – pattermeister

+1

भयानक! इसमें बहुत लंबा लगा, लेकिन मुझे खुशी है कि आखिर में वहां है! – Cheeso