思路
效果
实现步骤
使用框架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);
}
};