在web上使用GZIP压缩十六进制字符串(Javascript)

在web上使用GZIP压缩十六进制字符串(Javascript),javascript,html,hex,gzip,zlib,Javascript,Html,Hex,Gzip,Zlib,我有一个textarea,其中输入的值被转换为十六进制并连接起来,如下所示: 4f43 5441 1d00 0000 2400 0000 0004 0000 0200 0000 0000 0000 0000 0000 0000 0000 0200 0000 0206 0073 6b79 626f 780e 0073 6b79 626f 7865 732f 7768 6974 6502 0800 6d61 7074 6974 6c65 1900 4f47 5a20 4564 6974 6f72 2

我有一个textarea,其中输入的值被转换为十六进制并连接起来,如下所示:

4f43 5441 1d00 0000 2400 0000 0004 0000
0200 0000 0000 0000 0000 0000 0000 0000
0200 0000 0206 0073 6b79 626f 780e 0073
6b79 626f 7865 732f 7768 6974 6502 0800
6d61 7074 6974 6c65 1900 4f47 5a20 4564
6974 6f72 2066 6972 7374 2065 7665 7220
6d61 7003 6670 7300 0000 0000 0500 0200
0400 0300 0500 0700 0000 0044 0000 0044
0000 0044 0000 0000 0000 00ff 0000 0500
0000 0544 0000 0544 0000 0044 6e00 3200
0000 0000 0000 0200 0207 0007 0007 0001
0001 0001 0000 0202 0003 0004 0005 0006
0007 0000 0202 0003 0004 0005 0006 0007
0000 0202 0003 0004 0005 0006 0007 0000
0200 0000 0000 0007 0000 0000 0000 0100
0000 0000 0000 0000 0000 0000 0100 0000
0000 0000 0000 0000 0000 0100 0000 0000
0000 0000 0000 0000
我的目标是使用gzip“在线”(即不使用zlib命令行/nodejs)压缩这个十六进制,并使用blob使输出可供下载

这是我现在使用“”的尝试:

html

然而,PAKO(gzip)生成的输出与zlib生成的输出不匹配,它们不相同

有没有办法使两者的输出相同?或 如何使用JavaScript为gzip正确压缩十六进制字符串?

更新: @Blex提到了使用
缓冲区。从
开始,我认为它是nodejs的固有功能(我需要在浏览器中使用它),因此我尝试了,但是生成的文件仍然相同(仍然不同于zlib),但无论如何,我感谢您的帮助

比较

输入:“68656C6F20776F726C6421”(世界你好!)

zlib输出(mingw命令行):

1f8b 0800 4767 4c5e 0003 cb48 cdc9 c957
28cf 2fca 4951 0400 6dc2 b403 0C000 0000

巴基斯坦产出:

1f8b 0800 0000 0003 33b3 3033 354b
06c2 3423 0373 73b3 3473 2320 dbc4 c810
00b2 2eed 2a18 0000 00

编辑:在把这个答案写得有点太快之后,我注意到输出结果并不完全相同。有一个单字节的差异,对应于。zlib返回表示TOPS-20的
a
,Pako返回表示Unix的
3

zlib返回一个缓冲区,pako返回一个Uint8Array。要获取缓冲区,可以执行以下操作:

gzipresult = pako.gzip(hexresult, { level: 6 });
gzipbuffer = Buffer.from(gzipresult);
这将为您提供与zlib类似的精确输出。下面是一个简单的NodeJS脚本,用于测试和比较这两个脚本:

// Don't forget to `npm i -S pako`
const pako = require("pako");
const zlib = require("zlib");

const input = "Hello world!";
const hexStr = input.split("").reduce((hex,c)=>hex+=c.charCodeAt(0).toString(16).padStart(2,"0"),"");

zlib.gzip(hexStr, function(_, zlibResult) {
  const zlibHex = zlibResult.toString("hex");

  const pakoResult = pako.gzip(hexStr, { level: 6 });
  const pakoHex = Buffer.from(pakoResult).toString("hex");

  console.log("zlib", zlibHex);
  console.log("pako", pakoHex);
  console.log("Outputs are equal ===", zlibHex === pakoHex);
});


/*
Output:
pako 1f8b080000000000000333b13033354b06c23423037373b334732320dbc4c81000bde2d6f318000000
zlib 1f8b080000000000000a33b13033354b06c23423037373b334732320dbc4c81000bde2d6f318000000
                        ^
             actually not the same
Outputs are equal === false
*/

所以,事实证明,之所以会出现这种混乱,是因为我的输入,除了纯文本之外,还有几个空格字符(为了更好地查看,我把它们放进去了),这显然影响了转换为十六进制的结果。。。为了让它按我期望的方式工作,我只需删除所有空格字符,将其编码为十六进制,然后用pako压缩

var pako = window.pako;
function toHex(){
    input = document.getElementById("input").value.replace(/\s/g, "");
    hexresult = new Uint8Array(input.match(/.{2}/g).map(e => parseInt(e, 16)));

    gzipresult = pako.gzip(hexresult);
    download(gzipresult);
}

function download(data){
    downloadbtn = document.getElementById("downloadbtn");
    var blob = new Blob([ data ], {type : "application/octet-stream",});

    if (window.navigator.msSaveBlob) {
        navigator.msSaveBlob(blob, "output.gz");
    } else {
        var csvUrl = URL.createObjectURL(blob);
        $('#downloadbtn').attr({
            'download': "output.gz",
            'href': csvUrl
        })
    }
}

我做了一些阅读,因为我想找出为什么我的输出相差一个字节。我发现这个字节是用于声明OS类型的头。在我的例子中,zlib返回表示TOPS-20操作系统的
a
,Pako返回表示Unix的
3
。细节。如果这个字节是唯一的区别,这对我来说似乎总是如此,那么改变它就很容易了。你就是这样吗?如果没有,你能为同一个输入字符串提供示例输出,由两个libs处理吗?@blex好的,谢谢返回,我更新了帖子。不幸的是,几乎所有的输出都已更改。。。我认为需要注意的是,我正在使用升华文本的“十六进制”编码器打开文件。哦,我正在使用“mingw”在终端上运行
gzipoutput.gz
命令。使用nodejs和测试脚本都返回这些值​​同样,现在我开始认为我在mingw上使用的gzip版本已经过时了或者其他什么。。。但只有mingw生成的输出对我的使用是“有效的”,我认为压缩方法是相同的。。。
// Don't forget to `npm i -S pako`
const pako = require("pako");
const zlib = require("zlib");

const input = "Hello world!";
const hexStr = input.split("").reduce((hex,c)=>hex+=c.charCodeAt(0).toString(16).padStart(2,"0"),"");

zlib.gzip(hexStr, function(_, zlibResult) {
  const zlibHex = zlibResult.toString("hex");

  const pakoResult = pako.gzip(hexStr, { level: 6 });
  const pakoHex = Buffer.from(pakoResult).toString("hex");

  console.log("zlib", zlibHex);
  console.log("pako", pakoHex);
  console.log("Outputs are equal ===", zlibHex === pakoHex);
});


/*
Output:
pako 1f8b080000000000000333b13033354b06c23423037373b334732320dbc4c81000bde2d6f318000000
zlib 1f8b080000000000000a33b13033354b06c23423037373b334732320dbc4c81000bde2d6f318000000
                        ^
             actually not the same
Outputs are equal === false
*/
var pako = window.pako;
function toHex(){
    input = document.getElementById("input").value.replace(/\s/g, "");
    hexresult = new Uint8Array(input.match(/.{2}/g).map(e => parseInt(e, 16)));

    gzipresult = pako.gzip(hexresult);
    download(gzipresult);
}

function download(data){
    downloadbtn = document.getElementById("downloadbtn");
    var blob = new Blob([ data ], {type : "application/octet-stream",});

    if (window.navigator.msSaveBlob) {
        navigator.msSaveBlob(blob, "output.gz");
    } else {
        var csvUrl = URL.createObjectURL(blob);
        $('#downloadbtn').attr({
            'download': "output.gz",
            'href': csvUrl
        })
    }
}