如何在 JavaScript 中复制 GZipStream.Write()?
How to replicate GZipStream.Write() in JavaScript?
我有这段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
中重现这段代码,所以我尝试了 pako and node.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...
我还尝试了 pako
和 zlib
的一些不同选项,虽然有些选项的结果不同,但它从未匹配 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]
看起来这些库在编码 header:
的方式上有所不同
来自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
所以他们只是声明了一个不同的 OS 类型(TOPS-20?!,Unix,FAT)。
如果您确实需要,您可能必须修补 JS 库以将 "FAT" 输出为 OS。
查看 pako 源代码,您可能可以根据自己的喜好更改值,并且还提示了 "extra flags" 的用途:
来自 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);
调整关卡和攻略,还有osheader场,应该可以了!
我有这段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
中重现这段代码,所以我尝试了 pako and node.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...
我还尝试了 pako
和 zlib
的一些不同选项,虽然有些选项的结果不同,但它从未匹配 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]
看起来这些库在编码 header:
的方式上有所不同来自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
所以他们只是声明了一个不同的 OS 类型(TOPS-20?!,Unix,FAT)。 如果您确实需要,您可能必须修补 JS 库以将 "FAT" 输出为 OS。
查看 pako 源代码,您可能可以根据自己的喜好更改值,并且还提示了 "extra flags" 的用途: 来自 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);
调整关卡和攻略,还有osheader场,应该可以了!