سؤال

وكنت في حاجة إلى وسيلة لضغط الصور في صافي لذلك أنا بحثت في استخدام فئة صافي GZipStream (أو DeflateStream). ومع ذلك وجدت أن الضغط لم يكن ناجحا دائما، وأحيانا الصور من شأنه فك ضغط الجميلة وغيرها من الأوقات وأود أن الحصول على GDI + الخطأ إلى تلف شيء.

وبعد التحقيق في القضية وجدت أن الضغط كان لا يعيد كافة وحدات البايت أنه مضغوط. حتى لو كنت مضغوط 2257974 بايت أود أن أحصل أحيانا يعود بايت فقط 2257870 (الأعداد الحقيقية).

والشيء الأكثر المضحك هو أنه سيعمل في بعض الأحيان. لذلك أنا خلقت هذه الطريقة اختبار القليل الذي يضغط بايت 10 فقط، والآن أنا لا نعود أي شيء على الإطلاق.

وحاولت ذلك مع كل الطبقات ضغط GZipStream وDeflateStream وأنا مضاعفة فحص قانون بلدي عن الأخطاء المحتملة. حتى حاولت تحديد المواقع تيار ل0 والتنظيف كل تيارات ولكن مع عدم وجود الحظ.

وهنا هو رمز بلادي:

    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();
    }
هل كانت مفيدة؟

المحلول

وتحتاج إلى Close() وZipStream بعد إضافة كافة البيانات التي تريد ضغط. فإنه يحتفظ مخزن مؤقت بايت غير مكتوبة داخليا (حتى لو كنت Flush()) التي تحتاج إلى أن تكون مكتوبة.

وبصورة أعم، Stream هو IDisposable، لذا يجب عليك أيضا أن using كل ... (نعم، وأنا أعلم أن MemoryStream لن تفقد أي بيانات، ولكن إذا كنت لا ندخل في هذه العادة، وسوف يعض لك Streams غيرها).

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())
    { ... }
}

[عدل: محدث إعادة تعليق] إعادة لم using أشياء مثل MemoryStream - وهذا هو دائما متعة واحد، مع الكثير من الأصوات على جانبي السياج: ولكن ultimatey ...

و(الخطابي - ونحن جميعا نعرف الإجابة ...) كيف يتم MemoryStream تنفيذها؟ هو بايت [] (المملوكة من قبل .NET)؟ هو ملف الذاكرة المعنونة (المملوكة من قبل OS)؟

والسبب انك لم using هو لأنك السماح معرفة تفاصيل التنفيذ الداخلية تغيير الطريقة التي كود ضد API العام - أي كسرت لك مجرد قوانين التغليف. يقول API العام: أنا IDisposable. أنت تملكني؛ وبالتالي، فمن عملك لDispose() لي عندما كنت من خلال.

نصائح أخرى

وأيضا - نأخذ في الاعتبار DeflateStream في System.IO.Compression لا يطبق الخوارزمية يدحض الأكثر فعالية. إذا أردت، هناك بديل للBCL GZipStream وDeflateStream. ويتم تنفيذ ذلك في مكتبة إدارتها بشكل كامل على أساس قانون زليب، الذي ينفذ أفضل من المدمج في {انكماش، غزيب} ستريم في هذا الصدد. [ولكن ما زالت هناك حاجة لإغلاق () تيار للحصول على bytestream الكامل. ]

يتم شحن

وهذه الفئات تيار في الجمعية DotNetZlib، وهي متاحة في توزيع DotNetZip على HTTP: //DotNetZip.codeplex. كوم / .

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top