Java DeflaterInputStream и DeflaterOutputStream для C#

Рейтинг: 2Ответов: 1Опубликовано: 17.06.2023

Подскажите, есть ли нормальная реализация zlib в C# для .NET Framework 4.6.1 и ниже? Столкнулся с проблемой компрессии текста. Любая из испробованных версий реализации zlib алгоритма с GitHub этого алгоритма распаковывает байт массив в текст нормально, но после упаковки в сравнении с оригиналом байт массив в первых 2 байтах иной, а в конец имеются ещё какие-то 6 байт что в итоге делает его битым для последующих распаковки. При этом в Java версии всё работает нормально. Упакованный текст идентичен оригинальному до распаковки и упаковки обратно. Иными словами имея байт массив с упакованным текстом, как пример, я не могу получить на выходе средствами .NET идентичный байт массив после операций распаковки и упаковки.

введите сюда описание изображения

Код формы теста:

using System;
using System.IO;
using System.Text;
using System.Windows.Forms;
using Test_Compression.utils;
using zlib;

namespace Test_Compression
{
    public partial class Form1 : Form
    {
        // Source code of ZLIB
        // http://www.componentace.com/zlib_.NET.htm

        public Form1()
        {
            InitializeComponent();
        }

        private void buttonRun_Click(object sender, EventArgs e)
        {
            byte[] source = File.ReadAllBytes("original.bin");

            string sourceHex = HexUtil.printData(source);
            this.richTextBox1.Text = sourceHex;

            byte[] TextBlock;
            DecompressData(source, out TextBlock);

            string text = Encoding.Default.GetString(TextBlock);
            this.richTextBox3.Text = text;

            byte[] CompressedBlock;
            CompressData(TextBlock, out CompressedBlock);

            string compressedHex = HexUtil.printData(CompressedBlock);
            this.richTextBox2.Text = compressedHex;
        }

        public static void CompressData(byte[] inData, out byte[] outData)
        {
            using (MemoryStream outMemoryStream = new MemoryStream())
            using (ZOutputStream outZStream = new ZOutputStream(outMemoryStream, zlibConst.Z_DEFAULT_COMPRESSION))
            using (Stream inMemoryStream = new MemoryStream(inData))
            {
                CopyStream(inMemoryStream, outZStream);
                outZStream.finish();
                outData = outMemoryStream.ToArray();
            }
        }

        public static void DecompressData(byte[] inData, out byte[] outData)
        {
            using (MemoryStream outMemoryStream = new MemoryStream())
            using (ZOutputStream outZStream = new ZOutputStream(outMemoryStream))
            using (Stream inMemoryStream = new MemoryStream(inData))
            {
                CopyStream(inMemoryStream, outZStream);
                outZStream.finish();
                outData = outMemoryStream.ToArray();
            }
        }

        public static void CopyStream(Stream input, Stream output)
        {
            byte[] buffer = new byte[2000];

            int len;
            while ((len = input.Read(buffer, 0, buffer.Length)) > 0)
                output.Write(buffer, 0, len);

            output.Flush();
        }

        private void buttonClear_Click(object sender, EventArgs e)
        {
            this.richTextBox1.Clear();
            this.richTextBox2.Clear();
            this.richTextBox3.Clear();
        }
    }
}

Проект для проверки распаковки и упаковки прилагаю.

https://disk.yandex.ru/d/HpBzcz4QBWRUkA

Ответы

▲ 3Принят

Почитал инструкцию zlib и понял, что у вас просто не указан Z_SYNC_FLUSH.

То есть вот решение, нужно при компрессии указать

outZStream.FlushMode = zlibConst.Z_SYNC_FLUSH;

Итого получается:

private void buttonRun_Click(object sender, EventArgs e)
{
    byte[] source = File.ReadAllBytes("original.bin");

    string sourceHex = HexUtil.printData(source);
    this.richTextBox1.Text = sourceHex;

    byte[] TextBlock = DecompressData(source);

    string text = Encoding.UTF8.GetString(TextBlock);
    this.richTextBox3.Text = text;

    byte[] CompressedBlock = CompressData(TextBlock);

    string compressedHex = HexUtil.printData(CompressedBlock);
    this.richTextBox2.Text = compressedHex;
}

public static byte[] CompressData(byte[] inData)
{
    using (Stream inMemoryStream = new MemoryStream(inData))
    using (MemoryStream outMemoryStream = new MemoryStream())
    using (ZOutputStream outZStream = new ZOutputStream(outMemoryStream, zlibConst.Z_DEFAULT_COMPRESSION))
    {
        outZStream.FlushMode = zlibConst.Z_SYNC_FLUSH;
        CopyStream(inMemoryStream, outZStream);
        outZStream.finish();
        return outMemoryStream.ToArray();
    }
}

public static byte[] DecompressData(byte[] inData)
{
    using (Stream inMemoryStream = new MemoryStream(inData))
    using (MemoryStream outMemoryStream = new MemoryStream())
    using (ZOutputStream outZStream = new ZOutputStream(outMemoryStream)) 
    {
        CopyStream(inMemoryStream, outZStream);
        outZStream.finish();
        return outMemoryStream.ToArray();
    }
}

public static void CopyStream(Stream input, Stream output)
{
    byte[] buffer = new byte[8192];

    int len;
    while ((len = input.Read(buffer, 0, buffer.Length)) > 0)
        output.Write(buffer, 0, len);
}

Но странная конечно эта библиотека. Кстати, можете подключать не через Reference вручную, а установить как NuGet пакет, она там есть под названием zlib.net.

введите сюда описание изображения


Кстати, вот какого результата удалось добиться для .NET 7 вообще без сторонних библиотек. Класс ZLibStream доступен начиная с .NET 6 в BCL.

static void Main(string[] args)
{
    byte[] source = File.ReadAllBytes("original.bin");

    string sourceHex = HexUtil.printData(source);
    Console.WriteLine(sourceHex);

    byte[] bytes = DecompressData(source);

    string text = Encoding.UTF8.GetString(bytes);
    Console.WriteLine(/* text */);

    byte[] compressed = CompressData(bytes);

    string compressedHex = HexUtil.printData(compressed);
    Console.WriteLine(compressedHex);
}

public static byte[] CompressData(byte[] bytes)
{
    MemoryStream result = new();
    using (MemoryStream input = new(bytes))
    using (ZLibStream zs = new(result, CompressionLevel.Optimal))
    {
        input.CopyTo(zs);
        zs.Flush();
    }
    return result.ToArray();
}

public static byte[] DecompressData(byte[] bytes)
{
    MemoryStream result = new();
    using (MemoryStream input = new(bytes))
    using (ZLibStream zs = new(input, CompressionMode.Decompress))
    {
        zs.CopyTo(result);
    }
    return result.ToArray();
}

А вывод получился такой

0000: 78 9c 8a 0e 49 2d 2e 89 e5 e5 02 51 01 89 45 89    x...I-.....Q..E.
0010: b9 86 b6 7e f9 79 a9 20 01 08 3f b5 a8 28 b5 bc    ...~.y. ..?..(..
0020: 28 15 21 8c a1 0e 4d 80 97 2b 1a b7 99 c5 25 40    (.!...M..+....%@
0030: 7e 21 10 60 d7 8f cb bc 8c 74 3c 26 02 05 8a d3    ~!.`.....t<&....
0040: 70 39 08 ca 07 59 49 82 23 03 12 2b ca 92 2b ca    p9...YI.#..+..+.
0050: 20 a2 70 41 b8 a2 4a 98 aa f2 72 60 d0 00 31 ba     .pA..J...r`..1.
0060: 73 b3 f0 3b 97 68 01 a8 43 d3 89 31 0d 43 41 25    s..;.h..C..1.CA%
0070: ae c8 c1 6b 1c 86 f1 e9 59 19 84 62 3b 03 c5 44    ...k....Y..b;..D
0080: 42 9e 4b cf c8 42 12 a3 82 0b 29 70 5e 49 69 65    B.K..B....)p^Iie
0090: 49 29 7e 23 20 fc bc dc e4 b2 a4 e4 d1 68 1e 8d    I)~# ........h..
00A0: 66 fa 44 b3 89 09 66 44 9b 9a 99 62 08 82 84 08    f.D...fD...b....
00B0: 9b 6a 6a 36 f8 e3 3b 1d 9f 7b 48 70 a0 99 19 45    .jj6..;..{Hp...E
00C0: 71 0e 00 00 00 ff ff 03 00 ec 30 50 6c             q.........0Pl

0000: 78 9c 8a 0e 49 2d 2e 89 e5 e5 02 51 01 89 45 89    x...I-.....Q..E.
0010: b9 86 b6 7e f9 79 a9 20 01 08 3f b5 a8 28 b5 bc    ...~.y. ..?..(..
0020: 28 15 21 8c a1 0e 4d 80 97 2b 1a b7 99 c5 25 40    (.!...M..+....%@
0030: 7e 21 10 60 d7 8f cb bc 8c 74 3c 26 02 05 8a d3    ~!.`.....t<&....
0040: 70 39 08 ca 07 59 49 82 23 03 12 2b ca 92 2b ca    p9...YI.#..+..+.
0050: 20 a2 70 41 b8 a2 4a 98 aa f2 72 60 d0 00 31 ba     .pA..J...r`..1.
0060: 73 b3 f0 3b 97 68 01 a8 43 d3 89 31 0d 43 01 dc    s..;.h..C..1.C..
0070: 95 e8 fe c6 6b 1c 86 f1 e9 59 19 84 62 3b 03 c5    ....k....Y..b;..
0080: 44 42 9e 4b cf c8 42 12 a3 82 0b 29 70 5e 49 69    DB.K..B....)p^Ii
0090: 65 49 29 7e 23 20 fc bc dc e4 b2 a4 e4 d1 68 1e    eI)~# ........h.
00A0: 8d 66 fa e4 66 13 13 cc fc 6c 6a 66 8a 21 08 12    .f..f....ljf.!..
00B0: 22 6c aa a9 d9 e0 cf d6 e9 f8 dc 43 82 03 cd cc    "l.........C....
00C0: 28 ca da 00 00 00 00 ff ff 03 00 ec 30 50 6c       (...........0Pl

Видно, что отличается, но пакуется и распаковывается исправно. Как я понял, что это связано с разной версией реализизации алгоритма deflate в zlib. Это вроде-как не считается проблемой, так как работа распаковщика везде одинаковая, разница только в упаковщике.