2012-08-23 21 views
9

मेरे पास स्मृति में एक बड़ी वस्तु है जिसे मैं डेटाबेस में ब्लॉब के रूप में सहेजना चाहता हूं। मैं इसे सहेजने से पहले इसे संपीड़ित करना चाहता हूं क्योंकि डेटाबेस सर्वर आमतौर पर स्थानीय नहीं होता है। लेकिन जब मैं कुल कमांडर के साथ एक ही बाइट्स ज़िप इसे नीचे आकार हमेशा कम से कम 50% की कटौतीऑब्जेक्ट को क्रमबद्ध करने के लिए कैसे करें + इसे संपीड़ित करें और फिर तीसरे पक्ष की लाइब्रेरी के बिना deserialize decompressize?

using (var memoryStream = new MemoryStream()) 
{ 
    using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Compress)) 
    { 
    BinaryFormatter binaryFormatter = new BinaryFormatter(); 
    binaryFormatter.Serialize(gZipStream, obj); 

    return memoryStream.ToArray(); 
    } 
} 

:

यह है कि मैं क्या समय है। उपर्युक्त कोड के साथ यह 58 एमबी से 48 एमबी तक संपीड़ित होता है और 15 एमबी से छोटा कुछ भी बड़ा हो जाता है।

क्या मुझे किसी तृतीय-पक्ष ज़िप लाइब्रेरी का उपयोग करना चाहिए या .NET 3.5 में ऐसा करने का एक बेहतर तरीका है। मेरी समस्या के लिए कोई अन्य विकल्प?

संपादित करें:

बस के ऊपर एक कोड में एक बग मिला। एंजेलो आपके फिक्स के लिए धन्यवाद।

GZipStream संपीड़न अभी भी बहुत अच्छा नहीं है। मुझे टीसी 48% संपीड़न की तुलना में gZipStream द्वारा औसत 35% संपीड़न मिलता है।

मुझे पता नहीं बाइट्स की किस तरह मैं पिछले संस्करण :) के साथ बाहर हो रही थी है

EDIT2:

मैंने पाया है कि कैसे 47% 20% से संपीड़न में सुधार होगा। मुझे एक के बजाय दो मेमोरी स्ट्रीम का उपयोग करना पड़ा! क्या कोई यह समझा सकता है कि यह मामला क्यों है?

यहां 2 मेमोरी धाराओं वाला एक कोड है जो बहुत बेहतर संपीड़न करता है !!!

using (MemoryStream msCompressed = new MemoryStream()) 
using (GZipStream gZipStream = new GZipStream(msCompressed, CompressionMode.Compress)) 
using (MemoryStream msDecompressed = new MemoryStream()) 
{ 
    new BinaryFormatter().Serialize(msDecompressed, obj); 
    byte[] byteArray = msDecompressed.ToArray(); 

    gZipStream.Write(byteArray, 0, byteArray.Length); 
    gZipStream.Close(); 
    return msCompressed.ToArray(); 
} 
+1

मैं http: //www.icsharpcode का उपयोग करता हूं।बड़ी सफलता के साथ नेट/opensource/sharpziplib/Download.aspx। – Asken

उत्तर

2

GZipStream .NET 3.5 से आपको संपीड़न स्तर सेट करने की अनुमति नहीं है। यह पैरामीटर .NET 4.5 में पेश किया गया था, लेकिन मुझे नहीं पता कि यह आपको बेहतर परिणाम देगा या अपग्रेड आपके लिए उपयुक्त है या नहीं। पेटेंट AFAIK के कारण, एल्गोरिदम में निर्मित बहुत इष्टतम नहीं है। तो 3.5 में बेहतर संपीड़न प्राप्त करने का एकमात्र तरीका है एसडीके7zip या SharpZipLib द्वारा प्रदान की गई तीसरी पार्टी लाइब्रेरी का उपयोग करना है। आपके डेटा के बेहतर संपीड़न के लिए शायद आपको अलग-अलग libs के साथ थोड़ा प्रयोग करना चाहिए।

+1

gzip और डिफ्लेट में संपीड़न एल्गोरिदम आमतौर पर पेटेंट द्वारा अनगिनत होते हैं। पुराने देशी .NET संस्करण कम इष्टतम हैं क्योंकि पेटेंट के कारण उन्हें कम अनुकूलित किया गया है। –

1

डिफ़ॉल्ट इस्तेमाल किया CompressionLevel कम से कम http://msdn.microsoft.com/en-us/library/as1ff51s के अनुसार Optimal है, तो वहाँ कोई रास्ता नहीं GZipStream बताने के लिए "कड़ी मेहनत करनी" करने के लिए .. ऐसा नहीं है कि एक 3 पार्टी lib बेहतर होगा मेरे लिए लगता है।

मैंने व्यक्तिगत रूप से कभी भी GZipStream को संपीड़न के संदर्भ में 'अच्छा' नहीं माना - शायद वे स्मृति पदचिह्न को कम करने या अधिकतम गति को कम करने में प्रयास करते हैं। हालांकि, यह देखते हुए कि कैसे WindowsXP/WindowsVista/Windows7 एक्सप्लोरर में ज़िप फ़ाइलों को मूल रूप से संभालता है - ठीक है .. मैं नहीं कह सकता कि न तो यह तेज़ है, न ही अच्छा संपीड़न है .. मुझे आश्चर्य नहीं होगा अगर Win7 में एक्सप्लोरर वास्तव में GZipStream का उपयोग करता है - सब कुछ उन्होंने इसे कार्यान्वित किया है और ढांचे में डाल दिया है, इसलिए शायद वे इसे कई स्थानों पर उपयोग करते हैं (यानी, HTTP GZIP handling में उपयोग किया जाता है), इसलिए मैं इससे दूर रहूंगा, मुझे एक कुशल प्रसंस्करण की आवश्यकता है .. मैं ' मैंने इस विषय में कभी भी कोई गंभीर शोध नहीं किया है, क्योंकि मेरी कंपनी ने कई साल पहले एक अच्छा ज़िप-हैंडलर खरीदा था जब नेट शुरुआती दिनों में था।

संपादित करें:

अधिक refs:
http://dotnetzip.codeplex.com/workitem/7159 - लेकिन के रूप में चिह्नित "बंद/हल हो गई" 2009 में .. हो सकता है आप कुछ है कि कोड में की दिलचस्पी हो सकती?

हे, googling के कुछ ही मिनटों के बाद, ऐसा लगता है कि 7Zip कुछ सी # बाइंडिंग को उजागर करता है: http://www.splinter.com.au/compressing-using-the-7zip-lzma-algorithm-in/

संपादित # 2:

सिर्फ एक FYI करें .net4.5 abou: https://stackoverflow.com/a/9808000/717732

11

आप आपके कोड में एक बग है और स्पष्टीकरण एक टिप्पणी के लिए बहुत लंबा है, इसलिए मैं इसे एक उत्तर के रूप में प्रस्तुत करता हूं, भले ही यह आपके वास्तविक प्रश्न का उत्तर नहीं दे रहा हो।

आप बंद करने GZipStream अन्यथा आप संकुचित डेटा है कि आप deserialize करने में सक्षम नहीं होगा पैदा कर रहे के बाद memoryStream.ToArray() केवल कॉल करने के लिए की जरूरत है।

फिक्स्ड कोड इस प्रकार है:

using (var memoryStream = new System.IO.MemoryStream()) 
{ 
    using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Compress)) 
    { 
    BinaryFormatter binaryFormatter = new BinaryFormatter(); 
    binaryFormatter.Serialize(gZipStream, obj); 
    } 
    return memoryStream.ToArray(); 
} 

GZipStream मात्रा में अंतर्निहित बफर करने के लिए लिखते हैं और यह भी धारा के अंत में एक पाद लेख संलग्न कर देता है और यह केवल समय आप धारा को बंद में किया जाता है।

आप आसानी से निम्नलिखित कोड नमूना चलाकर यह साबित कर सकते हैं:

byte[] compressed; 
int[] integers = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 

var mem1 = new MemoryStream(); 
using (var compressor = new GZipStream(mem1, CompressionMode.Compress)) 
{ 
    new BinaryFormatter().Serialize(compressor, integers); 
    compressed = mem1.ToArray(); 
} 

var mem2 = new MemoryStream(compressed); 
using (var decompressor = new GZipStream(mem2, CompressionMode.Decompress)) 
{ 
    // The next line will throw SerializationException 
    integers = (int[])new BinaryFormatter().Deserialize(decompressor); 
} 
+0

मेरे स्वयं को एक बग मिला। आपका उत्तर पोस्ट करने के लिए धन्यवाद! बस संपादन पोस्ट कर रहा था :) – Marek

0

मूल प्रश्न .NET 3.5 से संबंधित था। तीन साल बाद, .NET 4.5 का उपयोग करने की अधिक संभावना है, मेरा उत्तर केवल 4.5 के लिए मान्य है। जैसा कि पहले उल्लेख किया गया है, संपीड़न एल्गोरिदम को .NET 4.5

के साथ अच्छे सुधार हुए हैं, आज, मैं कुछ स्थान बचाने के लिए अपने डेटा सेट को संपीड़ित करना चाहता था। तो मूल प्रश्न के समान लेकिन .NET4.5 के लिए। और क्योंकि मुझे याद है कि कई साल पहले डबल मेमोरीस्ट्रीम के साथ एक ही चाल का उपयोग करने के बाद, मैंने अभी कोशिश की है। मेरा डेटा सेट एक कंटेनर ऑब्जेक्ट्स है जिसमें कई हैंशसेट्स और स्ट्रिंग/int/डेटटाइम गुणों के साथ कस्टम ऑजेक्ट्स की सूचियां हैं। डेटा सेट में लगभग 45 000 ऑब्जेक्ट होते हैं और जब संपीड़न के बिना क्रमबद्ध होता है, तो यह 3500 केबी बाइनरी फ़ाइल बनाता है।

अब, GZipStream के साथ, प्रश्न में वर्णित एकल या डबल मेमोरीस्ट्रीम के साथ, या DeflateStream (जो 4.5 में zlib का उपयोग करता है) के साथ, मुझे हमेशा 818 केबी की फ़ाइल मिलती है। तो मैं सिर्फ डबल मेमोरीस्ट्रीम के साथ चाल की तुलना में जोर देना चाहता हूं .NET 4.5 के साथ बेकार हो गया।

 public static byte[] SerializeAndCompress<T, TStream>(T objectToWrite, Func<TStream> createStream, Func<TStream, byte[]> returnMethod, Action catchAction) 
     where T : class 
     where TStream : Stream 
    { 
     if (objectToWrite == null || createStream == null) 
     { 
      return null; 
     } 
     byte[] result = null; 
     try 
     { 
      using (var outputStream = createStream()) 
      { 
       using (var compressionStream = new GZipStream(outputStream, CompressionMode.Compress)) 
       { 
        var formatter = new BinaryFormatter(); 
        formatter.Serialize(compressionStream, objectToWrite); 
       } 
       if (returnMethod != null) 
        result = returnMethod(outputStream); 
      } 
     } 
     catch (Exception ex) 
     { 
      Trace.TraceError(Exceptions.ExceptionFormat.Serialize(ex)); 
      catchAction?.Invoke(); 
     } 
     return result; 
    } 

ताकि मैं अलग TStream उपयोग कर सकते हैं, उदाहरण के लिए:

आखिरकार, मेरी सामान्य कोड का पालन है

public static void SerializeAndCompress<T>(T objectToWrite, string filePath) where T : class 
    { 
     //var buffer = SerializeAndCompress(collection); 
     //File.WriteAllBytes(filePath, buffer); 
     SerializeAndCompress(objectToWrite,() => new FileStream(filePath, FileMode.Create), null,() => 
     { 
      if (File.Exists(filePath)) 
       File.Delete(filePath); 
     }); 
    } 

    public static byte[] SerializeAndCompress<T>(T collection) where T : class 
    { 
     return SerializeAndCompress(collection,() => new MemoryStream(), st => st.ToArray(), null); 
    }