有些项目需要兼容易语言以前的压缩数据、解压数据(数据操作支持库一),分析了一下封装格式,其实很简单
封装格式:
------------------------------------
[4字节魔数] 0x0D 0x0F 0x3E 0x03
[4字节长度] 原始字节长度(uint32,小端序)
[zlib压缩数据] 标准zlib流(含头78 9C... 尾部adler32)
------------------------------------
这是go代码的实现
[Golang] 纯文本查看 复制代码 package main
import (
"bytes"
"compress/zlib"
"encoding/binary"
"fmt"
"io"
"testing"
"time"
)
func TestCompress(t *testing.T) {
original := ".test1test2..."
// 压缩
compressed, err := ELanguageCompress([]byte(original))
if err != nil {
panic(err)
}
//解压
b, err := ELanguageDecompress(compressed)
if err != nil {
panic(err)
}
t.Log("解压后文本", string(b))
}
// 固定头部
var magic = []byte{0x0D, 0x0F, 0x3E, 0x03}
// ELanguageCompress 压缩数据
//
// 与易语言的 数据操作支持库一 结果一致
func ELanguageCompress(buf []byte) ([]byte, error) {
// 使用 zlib 压缩
var compBuf bytes.Buffer
zw := zlib.NewWriter(&compBuf)
_, err := zw.Write(buf)
if err != nil {
return nil, err
}
// 关闭会刷新并写入 zlib 流尾的 adler32
if err = zw.Close(); err != nil {
return nil, err
}
// 构造最终字节序列:magic + length(uint32 LE) + zlib bytes
var outBuf bytes.Buffer
outBuf.Write(magic)
// 原始字节长度写为 uint32 小端
var lenBuf [4]byte
binary.LittleEndian.PutUint32(lenBuf[:], uint32(len(buf)))
outBuf.Write(lenBuf[:])
// 写入 zlib 压缩数据
outBuf.Write(compBuf.Bytes())
return outBuf.Bytes(), nil
}
// ELanguageDecompress 解压数据
//
// 与易语言的 数据操作支持库一 结果一致
func ELanguageDecompress(buf []byte) ([]byte, error) {
// 校验长度与魔数
if len(buf) < 8 {
return nil, fmt.Errorf("数据长度不足")
}
if !bytes.Equal(buf[:4], magic) {
return nil, fmt.Errorf("魔数不匹配,非易语言压缩数据")
}
// 读取原始长度(虽然通常用不到,但保持一致性)
dataLen := binary.LittleEndian.Uint32(buf[4:8])
_ = dataLen // 仅保留供参考
// Step4: 取出 zlib 数据并解压
zlibData := buf[8:]
zr, err := zlib.NewReader(bytes.NewReader(zlibData))
if err != nil {
return nil, fmt.Errorf("zlib 解压失败: %v", err)
}
defer func() { _ = zr.Close() }()
decompBytes, err := io.ReadAll(zr)
if err != nil {
return nil, fmt.Errorf("读取解压数据失败: %v", err)
}
return decompBytes, nil
}
|