我使用C#工具收集一些大型日志信息。因此,我搜索了一种压缩这个巨大字符串的方法,我找到了this代码片段来完成这个伎俩:
public static string CompressString(string text)
{
byte[] buffer = Encoding.UTF8.GetBytes(text);
var memoryStream = new MemoryStream();
using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Compress, true))
{
gZipStream.Write(buffer, 0, buffer.Length);
}
memoryStream.Position = 0;
var compressedData = new byte[memoryStream.Length];
memoryStream.Read(compressedData, 0, compressedData.Length);
var gZipBuffer = new byte[compressedData.Length + 4];
Buffer.BlockCopy(compressedData, 0, gZipBuffer, 4, compressedData.Length);
Buffer.BlockCopy(BitConverter.GetBytes(buffer.Length), 0, gZipBuffer, 0, 4);
return Convert.ToBase64String(gZipBuffer);
}
在我的日志记录操作之后,C#工具将此压缩的String发送到node.js REST接口,该接口将其写入数据库。
现在(我对压缩的天真理解)我认为我可以简单地使用像nodejs端的那样的代码来解压缩它:
zlib.gunzip(Buffer.from(compressedLogMessage, 'base64'), function(err, uncompressedLogMessage) {
if(err) {
console.error(err);
}
else {
console.log(uncompressedLogMessage.toString('utf-8'));
}
});
但我收到错误:
{错误:错误的标题检查 在Zlib._handle.onerror(zlib.js:370:17)errno:-3,代码:' Z_DATA_ERROR' }
似乎压缩方法与解压缩功能不匹配。我希望任何具有压缩/解压缩知识的人都可以立即看到问题。
我可以改变或改进什么来使解压缩工作?
非常感谢!
==========更新===========
似乎消息接收和base64解码工作..
使用CompressString("Hello World")
会导致:
// before compression
"Hello World"
// after compression before base64 encoding
new byte[] { 11, 0, 0, 0, 31, 139, 8, 0, 0, 0, 0, 0, 0, 3, 243, 72, 205, 201, 201, 87, 8, 207, 47, 202, 73, 1, 0, 86, 177, 23, 74, 11, 0, 0, 0 }
// after base64 encoding
CwAAAB+LCAAAAAAAAAPzSM3JyVcIzy/KSQEAVrEXSgsAAAA=
在节点js侧:
// after var buf = Buffer.from('CwAAAB+LCAAAAAAAAAPzSM3JyVcIzy/KSQEAVrEXSgsAAAA=', 'base64');
{"buf":{"type":"Buffer","data":[11,0,0,0,31,139,8,0,0,0,0,0,0,3,243,72,205,201,201,87,8,207,47,202,73,1,0,86,177,23,74,11,0,0,0]}}
// after zlib.gunzip(buf, function(err, dezipped) { ... }
{错误:错误的标题检查 在Zlib._handle.onerror(zlib.js:370:17)errno:-3,代码:' Z_DATA_ERROR' }
===============更新2 ==================
@ 01binary的答案是对的!这是工作解决方案:
function toArrayBuffer(buffer) {
var arrayBuffer = new ArrayBuffer(buffer.length);
var view = new Uint8Array(arrayBuffer);
for (var i = 0; i < buffer.length; ++i) {
view[i] = buffer[i];
}
return arrayBuffer;
}
// Hello World (compressed with C#) => CwAAAB+LCAAAAAAAAAPzSM3JyVcIzy/KSQEAVrEXSgsAAAA=
var arrayBuffer = toArrayBuffer(Buffer.from('CwAAAB+LCAAAAAAAAAPzSM3JyVcIzy/KSQEAVrEXSgsAAAA=', 'base64'))
var zlib = require('zlib');
zlib.gunzip(Buffer.from(arrayBuffer, 4), function(err, uncompressedMessage) {
if(err) {
console.log(err)
}
else {
console.log(uncompressedMessage.toString()) // Hello World
}
});
答案 0 :(得分:2)
您找到的代码段似乎在输出流的开头写入了4个额外的字节,其中包含&#34;未压缩的&#34;原始数据的大小。原作者必须假设接收端的逻辑将读取这4个字节,知道它需要分配该大小的缓冲区,并将流的其余部分(+4偏移量)传递给gunzip。
如果您在节点端使用此签名: https://nodejs.org/api/buffer.html#buffer_class_method_buffer_from_arraybuffer_byteoffset_length
...然后传递4的字节偏移量.gzip流的前两个字节应该是{0x1F,0x8b},你可以在数组中看到这两个字节从偏移量4开始。一个简单的例子可以在这里找到zlib头: