React实现zip压缩解压

前阵子,项目上需要实现对zip包进行解压,生成文档树,然后进行修改文件内容,重新压缩生成zip压缩包。

步骤

  1. 使用zip.js进行读取zip文件
  2. 使用JSzip进行压缩

工具包使用说明

1. zip.js使用web worker实现
阮一峰-Web Worker 使用教程

Web Worker 的作用,就是为 JavaScript 创造多线程环境,允许主线程创建 Worker 线程,将一些任务分配给后者运行。在主线程运行的同时,Worker 线程在后台运行,两者互不干扰。等到 Worker 线程完成计算任务,再把结果返回给主线程。
这样做的好处是,一些计算密集型或高延迟的任务,被 Worker 线程负担了,主线程(通常负责 UI 交互)就会很流畅,不会被阻塞或拖慢。

2. zip.js 提供了文件的读写操作api
操作文档

读取zip

    // 动态加载zipjs文件资源
    async function loadzipjs() {
      setLoading(true);
      if (window.zip) return;
      await loadResources(['zipjs/zip.js', 'zipjs/zip-ext.js', 'zipjs/zip-fs.js'], false);
      window.zip.workerScriptsPath = `${window.location.origin}/zipjs/`;
    }

    // 读取zip目录
    function readZip(url) {
      if (!url) return;
      setLoading(true);
      window.zip.createReader(
        new window.zip.HttpReader(url),
        function (reader) {
          reader.getEntries(async function (entries) {
            const data = await getPathTree(entries, reader);
            updateTree(data);
            setLoading(false);
          });
        },
        function (error) {
          Notification.error({ message: '读取zip压缩包失败!' });
          console.log('readZip 读取zip失败!', error);
          setLoading(false);
          // onerror callback
        },
      );
    }

解析文件树

 // 根据文件路径获取文件目录
    async function getPathTree(entries, reader) {
      const tree = [];

      const _entries = await Promise.all(
        entries.map(async (entry) => {
          return new Promise((resolve) => {
            entry.getData(new window.zip.TextWriter(), function (text) {
              resolve({
                ...entry,
                content: text,
              });
            });
          });
        }),
      );

      reader.close();

      _entries.forEach((entry) => {
        const splitPath = entry.filename.replace(/^\/|\/$/g, '').split('/');
        let ptr = tree;
        for (let i = 0; i < splitPath.length; i++) {
          const node = {
            id: uuid(),
            name: splitPath[i],
            filename: entry.filename,
            directory: true,
          };
          if (i == splitPath.length - 1) {
            node.id = uuid();
            node.directory = false;
            node.entry = entry;
            node.content = entry.content;
          }
          const itemIndex = ptr.findIndex((item) => {
            return item.name === splitPath[i];
          });
          // 找不到则添加
          if (itemIndex < 0) {
            ptr.push({
              ...node,
              children: [],
            });
          }

          let index = itemIndex > -1 ? itemIndex : ptr.length - 1;
          ptr = ptr[index].children;
        }
      });
      return mapTree(tree, ({ node, children }) => ({
        ...node,
        children: isValidArray(children) ? children : null,
      }));
    }

生成zip

    // 生成zip
    function exportZip(treeData, zipName = 'result.zip') {
      var zip = new JSZip();
      forEachTree(treeData, ({ node }) => {
        if (!isNullOrUndefined(node.content)) {
          zip.file(node.filename, node.content);
        }
      });
      zip.generateAsync({ type: 'blob' }).then(function (blob) {
        download(blob, zipName);
      });
    }
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容