unzip-plugin
v1.0.0
Published
开箱即用的 ZIP 解压插件。内置 @zip.js/zip.js,支持超大文件、密码解密、流式解压、进度反馈、暂停/恢复/取消与内存管理。可用于浏览器直解 ESModule / UMD,亦提供 Vue3 Composition API 封装。
Maintainers
Readme
unzip-plugin
开箱即用的 ZIP 解压插件,基于 @zip.js/zip.js 实现。
超大文件流式解压 · 密码解密(ZIP 2.0 / AES)· 进度反馈 · 暂停 / 恢复 / 取消 · 内存管理
内置 zip 解压引擎,安装即用、无需 CDN。提供与框架无关的核心类 ZipUncompressor(可在原生 JS、Node 或任意框架中使用),并提供 Vue3 Composition API 封装。
目录
1. 安装
npm install unzip-plugin
# 或
yarn add unzip-plugin说明:底层
@zip.js/zip.js已随插件打包进dist,无需额外安装,也不依赖 CDN。
2. 引入(快速开始)
2.1 Vue3 全局注册(推荐)
// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import ZipPlugin from 'unzip-plugin'
createApp(App).use(ZipPlugin, {
defaultOptions: { password: 'your-password' },
}).mount('#app')注册后可通过全局属性 this.$zip(或 this.$zipUncompress)创建解压器实例:
// 任意组件内
const zip = this.$zip.create({ defaultOptions: { maxConcurrency: 4 } })
await zip.extractAll(file)2.2 局部使用 Composable
import { useZipUncompress } from 'unzip-plugin'
const { extractAll, parse, progress, status, error } = useZipUncompress()
const handleFile = async (file: File) => {
const result = await extractAll(file, { onProgress: (p) => console.log(p.percent) })
console.log(result.files)
}2.3 原生 JS / 非 Vue 使用核心类
核心类 ZipUncompressor 与框架无关,不依赖 Vue,可直接在原生 JS 或任意框架中使用:
import { ZipUncompressor } from 'unzip-plugin'
const uncompressor = new ZipUncompressor({
onProgress: (p) => console.log(`进度: ${p.percent}%`),
})
const result = await uncompressor.extractAll(zipFile)仓库内的
demo/目录即为一个基于 Vue3 + 原生 CSS 的完整示例,采用单文件组件并按标签页组织,完整覆盖src/下全部 API(核心类ZipUncompressor、useZipUncompress、ZipPlugin全局$zip、MemoryManager及所有UnzipOptions配置项),未引入任何第三方 UI 框架。运行npm run demo:dev即可预览。
3. API 文档
3.1 核心类 ZipUncompressor
供非 Vue / 原生 JS 使用。所有方法均以 Blob | ArrayBuffer | File | Response 作为输入源。
| 方法 | 类型 | 说明 |
| --- | --- | --- |
| parse | (source) => Promise<ZipEntry[]> | 解析 ZIP 结构,获取文件列表 |
| hasEncryptedFiles | (source) => Promise<boolean> | 是否包含加密文件 |
| validatePassword | (source, password) => Promise<PasswordValidationResult> | 验证密码 |
| extractAll | (source, options?) => Promise<UnzipResult> | 解压全部文件 |
| extractFiles | (source, paths, options?) => Promise<UnzipResult> | 解压指定路径文件 |
| extractStreaming | (source, options?) => AsyncGenerator<UnzipFile> | 流式逐个产出文件 |
| pause | () => void | 暂停 |
| resume | () => void | 恢复 |
| cancel | () => void | 取消 |
| reset | () => void | 重置状态 |
3.2 Composable useZipUncompress
| 参数名 | 类型 | 必填 | 默认值 | 说明 |
| --- | --- | --- | --- | --- |
| defaultOptions | Partial<UnzipOptions> | 否 | {} | 默认解压配置 |
| callbacks | UnzipCallbacks | 否 | {} | 全局回调(onProgress / onError / onComplete) |
3.3 配置参数 UnzipOptions
| 参数名 | 类型 | 必填 | 默认值 | 说明 | 使用场景 |
| --- | --- | --- | --- | --- | --- |
| password | string | 否 | '' | 解压密码 | 加密 ZIP 文件 |
| memoryThreshold | number | 否 | 536870912 | 内存阈值(字节):批量解压(extractAll/extractFiles)预估解压总大小超过时抛出 OUT_OF_MEMORY | 批量解压内存保护,默认 512MB |
| maxConcurrency | number | 否 | 3 | 最大并发解压数(extractAll/extractFiles 生效;extractStreaming 为顺序流式输出) | 批量解压加速 |
| filterPaths | string[] | 否 | [] | 仅解压命中的路径:支持完整路径、目录前缀或关键字子串;为空则解压全部 | 选择性解压 |
| skipEncrypted | boolean | 否 | false | 跳过加密文件 | 不解压加密文件 |
| onProgress | (progress: UnzipProgress) => void | 否 | - | 解压进度回调(按解压字节数回报) | 显示进度条 |
3.4 回调 UnzipCallbacks
| 回调名 | 类型 | 说明 | 使用场景 |
| --- | --- | --- | --- |
| onProgress | (progress: UnzipProgress) => void | 进度回调 | 进度条 |
| onError | (error: UnzipError) => void | 错误回调 | 错误提示 |
| onComplete | (result: UnzipResult) => void | 完成回调 | 解压后处理 |
3.5 返回值
useZipUncompress 返回:
| 属性 / 方法 | 类型 | 说明 |
| --- | --- | --- |
| status | Ref<UnzipStatus> | 解压状态 |
| progress | Ref<UnzipProgress> | 解压进度 |
| error | Ref<UnzipError \| null> | 错误信息 |
| result | Ref<UnzipResult \| null> | 解压结果 |
| entries | Ref<ZipEntry[]> | 解析后的文件条目 |
| isLoading | Ref<boolean> | 是否加载中 |
| isPaused | Ref<boolean> | 是否暂停 |
| canResume | Ref<boolean> | 是否可以恢复 |
| parse | (source) => Promise<ZipEntry[]> | 解析 |
| hasEncryptedFiles | (source) => Promise<boolean> | 检测加密 |
| validatePassword | (source, password) => Promise<PasswordValidationResult> | 验证密码 |
| extractAll | (source, options?) => Promise<UnzipResult> | 解压全部 |
| extractFiles | (source, paths, options?) => Promise<UnzipResult> | 解压选中 |
| extractStreaming | (source, options?) => AsyncGenerator<UnzipFile> | 流式解压 |
| pause / resume / cancel / reset | () => void | 控制方法 |
3.6 类型定义
type ZipSource = File | Blob | ArrayBuffer | Response;
interface ZipEntry {
name: string; // 文件名
path: string; // 文件路径
uncompressedSize: number; // 解压后大小
compressedSize: number; // 压缩后大小
compressionMethod: number;// 压缩方法
isEncrypted: boolean; // 是否加密
encryptionMethod: EncryptionMethod; // 加密算法
lastModified: Date; // 最后修改时间
crc32: number; // CRC32 校验
isDirectory: boolean; // 是否目录
}
interface UnzipFile {
name: string; // 文件名
path: string; // 文件路径
content: Blob | ArrayBuffer; // 文件内容
size: number; // 文件大小
type: string; // MIME 类型
isEncrypted: boolean;
lastModified: Date;
extractTime: number; // 解压耗时
}
interface UnzipResult {
success: boolean;
files: UnzipFile[];
skippedFiles?: string[]; // 跳过的加密文件
totalTime: number; // 总耗时(ms)
totalBytes: number; // 总字节数
}
enum UnzipStatus { IDLE | LOADING | PARSING | DECRYPTING | EXTRACTING | SUCCESS | ERROR | PAUSED }
enum UnzipErrorCode {
WRONG_PASSWORD | FILE_TOO_LARGE | UNSUPPORTED_ENCRYPT | OUT_OF_MEMORY |
INVALID_ZIP | CORRUPTED_FILE | DECRYPT_FAILED | WORKER_ERROR | USER_CANCELLED
}
enum EncryptionMethod { NONE | ZIP20 | AES128 | AES256 | UNKNOWN }
interface UnzipError {
code: UnzipErrorCode;
message: string;
detail?: { file?: string; entry?: ZipEntry; originalError?: Error };
}
interface PasswordValidationResult {
valid: boolean;
errorCode?: UnzipErrorCode;
message?: string;
encryptedFileCount?: number;
}
interface UnzipProgress {
status: UnzipStatus;
processedBytes: number;
totalBytes: number;
percent: number;
currentFile?: string;
processedFiles: number;
totalFiles: number;
elapsedTime: number;
estimatedTimeRemaining: number;
}4. 功能详解
4.1 基础解压
import { useZipUncompress } from 'unzip-plugin'
const { extractAll, progress, status, error } = useZipUncompress()
const handleFile = async (file: File) => {
try {
const result = await extractAll(file, {
onProgress: (p) => console.log(`进度: ${p.percent}%`),
})
console.log('解压完成:', result.files)
} catch (err) {
console.error('解压失败:', err)
}
}4.2 密码解压
import { useZipUncompress, UnzipErrorCode } from 'unzip-plugin'
const { validatePassword, extractAll } = useZipUncompress()
const handleExtract = async (file: File, password: string) => {
const validation = await validatePassword(file, password)
if (!validation.valid) return console.error('密码错误')
try {
const result = await extractAll(file, { password })
console.log('解压成功:', result)
} catch (err) {
// 通过 error 详情判断错误码
}
}4.3 流式解压(大文件)
import { useZipUncompress } from 'unzip-plugin'
const { extractStreaming } = useZipUncompress()
const handleLargeFile = async (file: File) => {
for await (const unzipFile of extractStreaming(file)) {
console.log('解压文件:', unzipFile.name)
await uploadToServer(unzipFile) // 逐个处理,降低内存
unzipFile.content = null // 及时释放内存
}
}4.4 按需解压(选择性)
import { useZipUncompress } from 'unzip-plugin'
const { parse, extractFiles } = useZipUncompress()
const previewZip = async (file: File) => {
const entries = await parse(file)
console.log('压缩内容:', entries)
}
const extractSelected = async (file: File, selectedPaths: string[]) => {
const result = await extractFiles(file, selectedPaths)
console.log('解压结果:', result)
}4.5 暂停 / 恢复 / 取消
import { useZipUncompress, UnzipStatus } from 'unzip-plugin'
const { extractAll, pause, resume, cancel, progress, status } = useZipUncompress()
const start = () => extractAll(file) // 开始
const pause1 = () => status.value === UnzipStatus.EXTRACTING && pause() // 暂停
const resume1 = () => status.value === UnzipStatus.PAUSED && resume() // 恢复
const cancel1 = () => cancel() // 取消4.6 多种输入源
import { ZipUncompressor } from 'unzip-plugin'
const zip = new ZipUncompressor()
// File / Blob / ArrayBuffer / Response 均可作为输入
await zip.extractAll(file) // <input type="file">
await zip.extractAll(await fetch(url).then(r => r.blob())) // 网络请求
await zip.extractAll(buf) // ArrayBuffer5. 错误处理
错误对象 UnzipError 包含 code、message 与可选 detail,可据此分场景处理:
import { UnzipErrorCode } from 'unzip-plugin'
const handleError = (error: UnzipError) => {
switch (error.code) {
case UnzipErrorCode.WRONG_PASSWORD: // 提示重新输入密码
break
case UnzipErrorCode.OUT_OF_MEMORY: // 降低并发或分片
break
case UnzipErrorCode.FILE_TOO_LARGE: // 改用流式解压
break
case UnzipErrorCode.INVALID_ZIP: // 提示文件格式错误
break
case UnzipErrorCode.USER_CANCELLED: // 用户取消,无需处理
break
default:
// 其他错误
}
}6. 浏览器兼容性
- 内置 zip.js 使用 Web Streams / 现代浏览器 API(
Blob.stream、CompressionStream) - 支持 Chrome 80+、Firefox 90+、Safari 14.1+、Edge 80+
- 如需支持旧版浏览器,请引入相应 polyfill
7. 常见问题 FAQ
Q1:解压大文件时页面卡顿?
使用 extractStreaming 流式处理,或在 UnzipOptions 中合理设置 memoryThreshold。
Q2:加密 ZIP(安卓生成)无法解压? 本插件使用 zip.js,自动识别 ZIP 2.0 传统加密与 AES 加密,提供正确密码即可解压;不支持分卷加密文件。
Q3:非 Vue 项目能用吗?
可以。直接使用与框架无关的核心类 ZipUncompressor,仅需浏览器环境,无需安装 Vue。
Q4:如何释放内存?
流式解压时逐个处理后立即将 file.content 置为 null;也可调用 reset() 重置状态并清理内存。
8. 版本说明
v1.0.0(初始发布)
- 内置 @zip.js/zip.js,完美兼容多种 ZIP 格式(含安卓生成的加密 ZIP)
- 提供框架无关的核心类
ZipUncompressor与 Vue3useZipUncompress封装 - 支持流式解压、密码解密(ZIP 2.0 / AES)、进度反馈、暂停 / 恢复 / 取消
- 内置内存管理器,可配置内存阈值
- 类型安全:完整 TypeScript 类型定义
- 提供基于 Vue3 + 原生 CSS 的完整演示 demo(覆盖 src 全部 API),亦支持原生 JS 通过核心类使用
License
MIT License,Copyright (c) 2026 SEMS Team。详见 LICENSE。
