场景描述
1.基于Zip实现ArrayBuffer类型数据的压缩与解压缩操作:应用开发过程中客户端应用与服务端频繁通信,当消息体积过大时,可以对数据流进行压缩操作,并对收发消息做CRC校验。
2.基于Gzip的数据的压缩与解压缩:将日志压缩写入gz文件;解压gz格式html、JSON、图片等各类资源文件。
方案描述
场景一、通信过程中的数据压缩、解压缩与校验
1.效果图
2.方案
1)通过getRawFileContentSync读取rawfile下文件存在arrayBufferIn中;
2)使用zip.compress将源缓冲区arrayBufferIn压缩至目标缓冲区arrayBufferOut;
3)使用socket.constructTCPSocketServerInstance创建TCPSocketServer连接,调用listen绑定IP地址和端口实现监听,通过tcpServer.on('connect')订阅连接,同时订阅TCPSocketConnection连接的接收消息事件,当收到用户端发送的数据后,先用adler32计算Adler-32校验和对传输数据进行校验,再调用zip.uncompress实现数据的解压缩,并将解压缩后的数据通过fs.write写入文件。
4)使用socket.constructTCPSocketInstance创建TCPSocket连接,tcp.bind绑定IP地址和端口,tcp.connect连接到指定IP和端口后计算数据传递前的Adler-32校验和,同时向服务端发送压缩后的目标数据。
3.核心代码
获取resources/rawfile目录下的文件内容
private arrayBufferIn: ArrayBufferLike = getContext().resourceManager.getRawFileContentSync("log.txt").buffer;
压缩实现
async function compressBuffer(arrayBufferIn: ArrayBuffer, arrayBufferOut: ArrayBuffer) {
let zip = zlib.createZipSync();
await zip.compress(arrayBufferOut, arrayBufferIn, 12).then((data) => {
console.info('compress success, data.destLen: ' + data.destLen + ", data.status: " + data.status);
}).catch((errData: base.BusinessError) => {
console.error(`errData is errCode:${errData.code} message:${errData.message}`);
})
}
解压缩实现
async function deCompressToFile(arrayBufferSource: ArrayBuffer) {
let arrayBufferDest = new ArrayBuffer(20);
let zip = zlib.createZipSync();
await zip.uncompress(arrayBufferDest, arrayBufferSource, 20).then((data) => {
console.info('uncompress success, data.destLen: ' + data.destLen + ", data.status: " + data.status);
let filePath = getContext().filesDir + "/mylog1.txt";
let file = fs.openSync(filePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
let writeLen = fs.writeSync(file.fd, arrayBufferDest);
fs.closeSync(file);
}).catch((errData: base.BusinessError) => {
console.error(`errData is errCode:${errData.code} message:${errData.message}`);
})
}
创建TCPSocketServer连接
let tcpServer: socket.TCPSocketServer = socket.constructTCPSocketServerInstance();
// 绑定本地IP地址和端口,进行监听
export function TCPServeListen() {
let ipAddress: socket.NetAddress = {} as socket.NetAddress;
ipAddress.address = "127.0.0.1";
ipAddress.port = 4651;
tcpServer.listen(ipAddress, (err: BusinessError) => {
if (err) {
console.log("Serve testTag-listen fail");
return;
}
console.log("Serve testTag-listen success");
});
}
订阅TCPSocketServer的连接事件
export function TCPServerConnect() {
// 订阅TCPSocketServer的connect事件
tcpServer.on("connect", (client: socket.TCPSocketConnection) => {
// 订阅TCPSocketConnection相关的事件
client.on("close", () => {
console.log("Serve testTag-on close success");
});
client.on("message", (value: SocketInfo) => {
let checksum = zlib.createChecksumSync()
//计算Adler-32校验和
checksum.adler32(0, value.message).then(data => {
console.info('receive Adler-32校验和: ', data);
})
//解压数据
deCompressToFile(value.message)
});
});
}
创建TCPSocket连接,并向指定IP地址和端口发送数据。
let tcp: socket.TCPSocket = socket.constructTCPSocketInstance();
// 绑定本地IP地址和端口。
let ipAddress: socket.NetAddress = {} as socket.NetAddress;
ipAddress.address = "127.0.0.1";
ipAddress.port = 1234;
tcp.bind(ipAddress, (err: BusinessError) => {
if (err) {
console.log('testTag-bind fail');
return;
}
console.log('testTag-bind success');
// 连接到指定的IP地址和端口。
ipAddress.address = "127.0.0.1";
ipAddress.port = 4651;
let tcpConnect: socket.TCPConnectOptions = {} as socket.TCPConnectOptions;
tcpConnect.address = ipAddress;
tcpConnect.timeout = 6000;
tcp.connect(tcpConnect, (err: BusinessError) => {
if (err) {
console.log('testTag-connect fail');
return;
}
// 发送数据
let tcpSendOptions: socket.TCPSendOptions = {} as socket.TCPSendOptions;
tcpSendOptions.data = messag;
tcp.send(tcpSendOptions, (err: BusinessError) => {
if (err) {
console.log('testTag-send fail');
return;
}
console.log('testTag-send success');
})
console.log('testTag-connect success');
});
});
场景二、基于Zip实现大文件的压缩与解压缩
1.效果图
2.方案
1)压缩方案:使用zlib.createZipSync创建压缩对象并初始化压缩流,循环判断当前文件是否已读取压缩完成,如未完成,则继续读取文件,使用zip.deflate压缩到buffer中并继续写入文件;
2)解压缩方案:使用zlib.createZipSync创建解压缩对象并初始化压缩流,循环判断当前文件是否已读取解压完成,如未完成,则继续读取文件,使用zip.inflate继续解压到buffer中并写入解压后的文件中。
3.核心代码
文件压缩实现
export async function deflateFile(src: fs.File, dest: fs.File) {
let flush = zlib.CompressFlushMode.NO_FLUSH; //默认值,表示正常操作
let strm: zlib.ZStream = {};
const BUFLEN = 4096;
let inBuf = new ArrayBuffer(BUFLEN);
let outBuf = new ArrayBuffer(BUFLEN);
let zip = zlib.createZipSync();//创建压缩对象
let initStatus = zip.deflateInit(strm, zlib.CompressLevel.COMPRESS_LEVEL_BEST_SPEED);
console.debug('deflateInit ret: ' + (await initStatus).valueOf());
do {
let readLen = fs.readSync(src.fd, inBuf);
console.debug("readSync readLen: " + readLen);
flush = readLen == 0 ? zlib.CompressFlushMode.FINISH : zlib.CompressFlushMode.NO_FLUSH;
strm.availableIn = readLen;
strm.nextIn = inBuf;
do {
strm.availableOut = BUFLEN;
strm.nextOut = outBuf;
try {
let deflateStatus = zip.deflate(strm, flush);
console.debug('deflate ret: ' + (await deflateStatus).valueOf());
let innerStrm = zip.getZStream();
strm.availableIn = (await innerStrm).availableIn;
strm.nextIn = (await innerStrm).nextIn;
strm.availableOut = (await innerStrm).availableOut;
strm.nextOut = (await innerStrm).nextOut;
strm.totalIn = (await innerStrm).totalIn;
strm.totalOut = (await innerStrm).totalOut;
if (strm.availableOut != undefined) {
let have = BUFLEN - strm.availableOut;
let writeLen = fs.writeSync(dest.fd, outBuf, { length: have });
console.debug(`writeSync writeLen: ${writeLen}`);
}
} catch (err) {
console.debug('deflate err: ' + JSON.stringify(err));
}
} while (strm.availableOut == 0);
} while (flush != zlib.CompressFlushMode.FINISH);
zip.deflateEnd(strm);
}
文件解压实现
export async function inflateFile(src: fs.File, dest: fs.File) {
let status: zlib.ReturnStatus = zlib.ReturnStatus.OK;
let strm: zlib.ZStream = {};
const BUFLEN = 4096;
let inBuf = new ArrayBuffer(BUFLEN);
let outBuf = new ArrayBuffer(BUFLEN);
let zip = zlib.createZipSync();//创建压缩对象
let initStatus = zip.inflateInit(strm);
console.debug('inflateInit ret: ' + (await initStatus).valueOf());
do {
let readLen = fs.readSync(src.fd, inBuf);
console.debug("readSync readLen: " + readLen);
if (readLen == 0) {
break;
}
strm.availableIn = readLen;
strm.nextIn = inBuf;
do {
strm.availableOut = BUFLEN;
strm.nextOut = outBuf;
try {
let inflateStatus = zip.inflate(strm, zlib.CompressFlushMode.NO_FLUSH);
console.debug('inflate ret: ' + (await inflateStatus).valueOf());
let innerStrm = zip.getZStream();
strm.availableIn = (await innerStrm).availableIn;
strm.nextIn = (await innerStrm).nextIn;
strm.availableOut = (await innerStrm).availableOut;
strm.nextOut = (await innerStrm).nextOut;
strm.totalIn = (await innerStrm).totalIn;
strm.totalOut = (await innerStrm).totalOut;
if (strm.availableOut != undefined) {
let have = BUFLEN - strm.availableOut;
let writeLen = fs.writeSync(dest.fd, outBuf, { length: have });
console.debug(`writeSync writeLen: ${writeLen}`);
}
} catch (err) {
console.debug('inflate err: ' + JSON.stringify(err));
}
} while (strm.availableOut == 0)
} while (status != zlib.ReturnStatus.STREAM_END.valueOf())
zip.inflateEnd(strm);
}
场景三、基于GZip实现将字符串压缩写入gz文件
1.效果图
2.方案
使用createGZipSync创建GZip对象,通过gzip.gzwrite实现将buffer压缩进gz文件中
3.核心代码
let filePath = getContext().filesDir + "/hilog.gz";
let gzip = zlib.createGZipSync();
await gzip.gzopen(filePath, "wb");
let str = 'gzwrite success.';
let bufferWithData = new ArrayBuffer(str.length);
let uint8View = new Uint8Array(bufferWithData);
for (let i = 0; i < str.length; i++) {
uint8View[i] = str.charCodeAt(i);
}
let result = await gzip.gzwrite(bufferWithData, str.length);
await gzip.gzclose();
场景四、解压读取html文件并加载
1.效果图
2.方案
1)通过createGZipSync创建GZip对象,使用gzread读取gz文件中并解压到buffer中,然后转为字符串类型;
2)通过webController加载html页面
3.核心代码
1)解压读取gz文件
let filePath = getContext().resourceDir + "/html.gz";
let fileStat = fs.statSync(filePath).size;
let gzip = zlib.createGZipSync();
await gzip.gzopen(filePath, "rb");
let readBuffer = new ArrayBuffer(fileStat);
let result = await gzip.gzread(readBuffer);
await gzip.gzclose();
let textDecoder = util.TextDecoder.create('utf-8');
let uint8 = new Uint8Array(readBuffer);
this.webData = textDecoder.decodeToString(uint8);
2)加载html页面
this.webController.loadData(
this.webData,
"text/html",
"UTF-8"
);
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。