React Native还原QT zlib compress2压缩文件时头部校验错误求助
问题描述
在QT环境中通过zlib的compress2()函数生成的二进制压缩文件,在React Native应用中使用react-zlib-js库的inflate()方法解压时,出现「Error: incorrect header check」错误。尝试过inflateSync、inflateRaw等方法,也尝试移除文件前4字节,但问题依旧。不过在Node.js环境中使用node:zlib可以正常解压该文件,需要解决React Native端的解压问题。
QT压缩代码
QByteArray qCompress(const uchar* data, int nbytes, int compressionLevel) { if (nbytes == 0) { return QByteArray(4, '\0'); } if (!data) { qWarning("qCompress: Data is null"); return QByteArray(); } if (compressionLevel < -1 || compressionLevel > 9) compressionLevel = -1; ulong len = nbytes + nbytes / 100 + 13; QByteArray bazip; int res; do { bazip.resize(len + 4); res = ::compress2((uchar*)bazip.data()+4, &len, data, nbytes, compressionLevel); switch (res) { case Z_OK: bazip.resize(len + 4); bazip[0] = (nbytes & 0xff000000) >> 24; bazip[1] = (nbytes & 0x00ff0000) >> 16; bazip[2] = (nbytes & 0x0000ff00) >> 8; bazip[3] = (nbytes & 0x000000ff); break; case Z_MEM_ERROR: qWarning("qCompress: Z_MEM_ERROR: Not enough memory"); bazip.resize(0); break; case Z_BUF_ERROR: len *= 2; break; } } while (res == Z_BUF_ERROR); return bazip; }
React Native原解压代码
const zlib = require("react-zlib-js"); import { writeFile, readFile } from "react-native-fs"; async function decompressBinaryDatabaseFile() { try { const buffer = await readFile(fullBinaryFileName, "base64"); await zlib.inflate(buffer, { raw: true }, (err: any, result: string) => { if (err) { console.log("Error decompressing database file: ", err); } else { console.log("Decompressed database file: ", result); writeFile(fullDatabaseFileName, result, "base64") .then((success) => { console.log("FILE WRITTEN!"); openDatabase(); }) .catch((err) => { console.log(err.message); }); } }); } catch (error) { console.log("Error decompressing database file: ", error); } }
Node.js正常解压代码
const zlib = require('node:zlib'); const fs = require('node:fs'); const file = "./4826dd1c8821d8e08030a80ed0c12ef9"; var data = fs.readFileSync(file, "hex"); data = data.slice(4); zlib.inflate(data, function(err, buffer) { if (err) throw err; fs.writeFileSync("output.db", buffer); });
解决方法
问题根源
- QT的
compress2()生成的是原始deflate格式的压缩数据(无zlib标准头部和校验尾部),同时在数据前添加了4字节的原始数据长度标识。 - React Native端原代码的问题:直接传递base64字符串给zlib方法,未转成二进制数组;移除前4字节的操作未作用在正确的二进制数据上;未明确指定原始deflate模式的参数。
修改后的React Native解压代码
const zlib = require("react-zlib-js"); import { writeFile, readFile } from "react-native-fs"; // base64转Uint8Array function base64ToUint8Array(base64) { const binaryString = atob(base64); const bytes = new Uint8Array(binaryString.length); for (let i = 0; i < binaryString.length; i++) { bytes[i] = binaryString.charCodeAt(i); } return bytes; } // Uint8Array转base64 function uint8ArrayToBase64(bytes) { const binaryString = String.fromCharCode(...bytes); return btoa(binaryString); } async function decompressBinaryDatabaseFile() { try { const base64Buffer = await readFile(fullBinaryFileName, "base64"); // 将base64转为二进制数组 const fullData = base64ToUint8Array(base64Buffer); // 移除前4字节的原始长度标识 const compressedData = fullData.slice(4); // 使用inflateRaw处理原始deflate格式数据 zlib.inflateRaw(compressedData, (err, result) => { if (err) { console.log("Error decompressing database file: ", err); return; } // 将解压后的二进制数据转为base64写入文件 const outputBase64 = uint8ArrayToBase64(result); writeFile(fullDatabaseFileName, outputBase64, "base64") .then(() => { console.log("FILE WRITTEN!"); openDatabase(); }) .catch((err) => { console.log(err.message); }); }); } catch (error) { console.log("Error decompressing database file: ", error); } }
关键修改点
- 新增base64与Uint8Array的互转函数,确保zlib处理的是二进制数组而非字符串
- 正确移除压缩数据前4字节的原始长度标识
- 使用
inflateRaw()方法(或inflate()配合{raw: true}参数)处理原始deflate格式的压缩数据
内容的提问来源于stack exchange,提问作者Jeevo
相关产品推荐
相关产品推荐

