【问题标题】:How to replicate GZipStream.Write() in JavaScript?如何在 JavaScript 中复制 GZipStream.Write()?
【发布时间】:2019-12-22 14:53:39
【问题描述】:

我有这段C#代码:

public static byte[] TestGzip(string text)
    {
        byte[] bytes = Encoding.UTF8.GetBytes(text);
        MemoryStream memoryStream1 = new MemoryStream();

        using (GZipStream gzipStream = new GZipStream(memoryStream1, CompressionMode.Compress, true))
            gzipStream.Write(bytes, 0, bytes.Length);

        memoryStream1.Position = 0L;
        byte[] buffer = new byte[memoryStream1.Length];
        memoryStream1.Read(buffer, 0, buffer.Length);

        return buffer;
    }

我想在JavaScript 中重现这段代码,所以我尝试了pakonode.js zlib
以下是它们的输出与GZipStream 以及彼此之间的细微差别:

const zlib = require('zlib');
const pako = require('pako');
const cc = str => [...str].map(c => c.charCodeAt(0) & 255);

// C# (this is what I want)
Program.TestGZip("a")                 // [31, 139, 8, 0, 0, 0, 0, 0, 4, 0, 75, 4, 0, 67, 190, 183, 232, 1, 0, 0, 0]

// JS
pako.gzip("a")                        // [31, 139, 8, 0, 0, 0, 0, 0, 0, 3, 75, 4, 0, 67, 190, 183, 232, 1, 0, 0, 0] Uint8Array(21)
pako.gzip([97])                       // same...
pako.gzip(new Uint8Array([97]))       // same...
pako.gzip(cc("a"))                    // same...

zlib.gzipSync("a")                    // [31, 139, 8, 0, 0, 0, 0, 0, 0, 10, 75, 4, 0, 67, 190, 183, 232, 1, 0, 0, 0] Buffer(21)
zlib.gzipSync(new Uint8Array([97]))   // same...

我还尝试了pakozlib 的一些不同选项,虽然有些选项的结果不同,但它从未匹配C# 结果:

// different options
zlib.gzipSync("a", {level: 1})        // [31, 139, 8, 0, 0, 0, 0, 0, 4, 10, 75, 4, 0, 67, 190, 183, 232, 1, 0, 0, 0]
zlib.gzipSync("a", {level: 9})        // [31, 139, 8, 0, 0, 0, 0, 0, 2, 10, 75, 4, 0, 67, 190, 183, 232, 1, 0, 0, 0]
zlib.gzipSync("a", {strategy: 2|3})   // [31, 139, 8, 0, 0, 0, 0, 0, 4, 10, 75, 4, 0, 67, 190, 183, 232, 1, 0, 0, 0]

pako.gzip("a", {level: 1})            // [31, 139, 8, 0, 0, 0, 0, 0, 4, 3, 75, 4, 0, 67, 190, 183, 232, 1, 0, 0, 0]
pako.gzip("a", {level: 9})            // [31, 139, 8, 0, 0, 0, 0, 0, 2, 3, 75, 4, 0, 67, 190, 183, 232, 1, 0, 0, 0]
pako.gzip("a", {strategy: 2|3})       // [31, 139, 8, 0, 0, 0, 0, 0, 4, 3, 75, 4, 0, 67, 190, 183, 232, 1, 0, 0, 0]

那我该怎么办?
为什么会有这些细微的差别?
如何获得准确的GZipStream.Write() 输出?

修复(感谢@Sebastian):

pako.gzip("a", {strategy: 2, header:{os: 0}})
pako.gzip("a", {strategy: 3, header:{os: 0}})

// weirdly enough, just passing an empty header object works as well:
pako.gzip("a", {strategy: 2, header:{}})
pako.gzip("a", {strategy: 3, header:{}})

// all outputs are exactly like GZipStream.Write():
// [31, 139, 8, 0, 0, 0, 0, 0, 4, 0, 75, 4, 0, 67, 190, 183, 232, 1, 0, 0, 0]

【问题讨论】:

    标签: javascript c# zlib gzipstream pako


    【解决方案1】:

    看起来这些库在对标头进行编码的方式上有所不同:

    来自http://www.onicos.com/staff/iz/formats/gzip.html

    Offset   Length   Contents
     ...
      8      1 byte   extra flags (depend on compression method)
      9      1 byte   OS type
    

    所以他们只是声明了不同的操作系统类型(TOPS-20?!、Unix、FAT)。 如果你真的想要的话,你可能不得不修补 JS 库以将“FAT”输出为 OS。

    查看 pako 来源,您可能可以根据自己的喜好更改值,并且还有一个提示是“额外标志”的用途: 来自Github

    put_byte(s, s.level === 9 ? 2 :
                        (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
                         4 : 0));
    put_byte(s, s.gzhead.os & 0xff);
    

    调整关卡和策略,以及os头字段,你应该好好去!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-05-30
      • 2017-11-17
      • 2019-09-18
      • 2014-09-27
      • 1970-01-01
      • 2014-02-28
      • 2014-03-03
      • 2013-12-08
      相关资源
      最近更新 更多