【入门到精通】鸿蒙next开发:基于@ohos.zlib的数据压缩与解压缩

往期鸿蒙5.0全套实战文章必看:(文中附带全栈鸿蒙5.0学习资料)


基于@ohos.zlib的数据压缩与解压缩

场景描述

1、基于Zip实现ArrayBuffer类型数据的压缩与解压缩操作:应用开发过程中客户端应用与服务端频繁通信,当消息体积过大时,可以对数据流进行压缩操作,并对收发消息做CRC校验

2、基于Gzip的数据的压缩与解压缩:将日志压缩写入gz文件;解压gz格式html、JSON、图片等各类资源文件。

方案描述

场景一、通信过程中的数据压缩、解压缩与校验

1.效果图

43.png

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.核心代码

1)获取resources/rawfile目录下的文件内容。

private arrayBufferIn: ArrayBufferLike = getContext().resourceManager.getRawFileContentSync("log.txt").buffer;

2)压缩实现。

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}`); 
  }) 
}

3)解压缩实现。

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}`); 
  }) 
}

4)创建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"); 
  }); 
}

5)订阅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) 
    }); 
  }); 
}

6)创建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.效果图

44.png

2.方案

1)压缩方案:使用zlib.createZipSync创建压缩对象并初始化压缩流,循环判断当前文件是否已读取压缩完成,如未完成,则继续读取文件,使用zip.deflate压缩到buffer中并继续写入文件;

2)解压缩方案:使用zlib.createZipSync创建解压缩对象并初始化压缩流,循环判断当前文件是否已读取解压完成,如未完成,则继续读取文件,使用zip.inflate继续解压到buffer中并写入解压后的文件中。

3.核心代码

1)文件压缩实现。

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); 
}

2)文件解压实现。

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.效果图

45.png

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.效果图

46.png

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" 
);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值