使用C#片段

时间:2017-05-11 09:21:45

标签: c# node.js zlib compression

我使用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
  }
});

1 个答案:

答案 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头:

Zlib compression incompatibile C vs C# implementations