Java DeflaterInputStream и DeflaterOutputStream для C#
Подскажите, есть ли нормальная реализация 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
Ответы (1 шт):
Почитал инструкцию 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. Это вроде-как не считается проблемой, так как работа распаковщика везде одинаковая, разница только в упаковщике.

