前端zip压缩包文件目录预览

思路

效果

 实现步骤

使用框架react ts 

 node版本16.15.0

 1. 安装库

jszip是zip压缩包解压读取压缩包内容的库

iconv-lite是解决zip压缩包中文字符串乱码的库

  npm install  jszip@3.10.1 --save 
  npm install iconv-lite@0.6.3 --save

2. 引入

import JSZip from 'jszip';
import iconv from 'iconv-lite'
import React, { useRef, useState } from 'react';

3. jsx内容

const ZpiLook: React.FC = () => {
  const fileInputRef = useRef(null);
  const [zipContents, setZipContents] = useState<any>(null);

  // 在这里添加内容4

  return (
    <div>
      <h1>ZIP File Preview</h1>
      <input type="file" ref={fileInputRef} onChange={handleFileSelect} />
      {zipContents && renderTree(zipContents)}
    </div>
  );
};

4. 目录信息

解析zip获取目录信息,处理信息为树结构

 // 把获取的目录进行第一次处理,转成树结构
 const zipFilesToTree = (files: { [key: string]: JSZip.JSZipObject }): any[] => {
    const root: any = { name: 'root', children: [] };

    Object.keys(files).forEach((fileName) => {
      const file = files[fileName];
      const path = fileName.split('/');
      let currentNode = root;

      for (let i = 1; i < path.length - 1; i++) {
        const folderName = path[i];
        let foundChild = currentNode.children.find((child: any) => child.name === folderName);

        if (!foundChild) {
          foundChild = { name: folderName, children: [] };
          currentNode.children.push(foundChild);
        }
        currentNode = foundChild;
      }

      currentNode.children.push({
        name: path[path.length - 1],
        isFile: true,
        content: file,
      });
    });

    return [root];
  };

// 渲染树形结构jsx展示的函数
  const renderTree = (tree: any[]): React.ReactNode => {
    if (!tree || tree.length === 0) {
      return null;
    }

    return (
      <ul>
        {
          tree.map((item: any, index: number) => <li key={index} style={{ marginLeft: 10, listStyleType: item?.isFile ? 'disc' : 'circle' }}>
            {item.name}
            <div style={{ marginLeft: 10 }}>
              {renderTree(item.children)}
            </div>
          </li>)
        }
      </ul>
    );
  };

// 递归函数来过滤掉name为空的对象
  const filterEmptyNames = (node: any) => {
    // 过滤当前层级的节点
    let filteredChildren = node?.children?node?.children.filter((child: any) => child.name !== ""):[];

    // 对每个子节点递归调用filterEmptyNames
    filteredChildren = filteredChildren.length>0?filteredChildren.map((child: any) => {
      if (child.children && child.children.length > 0) {
        return filterEmptyNames(child);
      }
      return child;
    }):[];

    // 返回过滤后的节点
    return { ...node, children: filteredChildren };
  }
// !!!!!!!!!!!!!!!!!!
 // 因为 File 类本身就继承自 Blob 类。这意味着 File 对象已经是一个 Blob,无需进行任何转换。
  const handleFileSelect = async (event: React.ChangeEvent<HTMLInputElement>) => {
    if (event.target.files && event.target.files.length > 0) {
      const zipFile = event.target.files[0];
      const zip = new JSZip();
      //zipFile后续也可以是就请求后端得到的blob数据流
      const zipaLoad = await zip.loadAsync(zipFile, {
        decodeFileName: function (bytes) {
          // 使用iconv-lite解码,解决中文乱码问题
          return iconv.decode(bytes as Buffer, 'gbk')  
        }
      });

      const zipContents = await zip.files;
      // 转换ZIP文件内容为树形结构
      const zipFilesTree = zipFilesToTree(zipContents);
      const tree = zipFilesTree[0];

      const filteredTree = tree.children.filter((dd:any)=>{
        if(dd?.name){
          return dd
        }
      }).map(filterEmptyNames);
      setZipContents(filteredTree);
    }
  };

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值