Windows 批量解压 TAR 文件脚本:支持文件数量校验、断点续解压和自动跳过
文章目录
- 一、需求说明
- 二、脚本功能
- 三、为什么使用 7-Zip
- 1. 7-Zip 支持命令行调用
- 2. 方便读取 tar 包内部文件列表
- 3. 支持跳过已存在文件,适合断点续解压
- 4. 对 tar 文件支持比较稳定
- 5. 适合处理大量小文件场景
- 四、完整 BAT 脚本
- 五、使用前需要修改的地方
- 六、脚本运行逻辑说明
- 1. 检查 7-Zip 是否存在
- 2. 检查源目录是否存在
- 3. 检查目标盘符是否可访问
- 4. 统计 tar 文件总数
- 5. 每个 tar 文件解压到同名目录
- 七、文件数量校验逻辑
- 1. 统计 tar 包内部文件数量
- 2. 统计目标目录已有文件数量
- 3. 判断是否需要解压
- 八、关于“重新解压”的理解
- 九、完成标记文件的作用
- 十、运行效果示例
- 十一、需要注意的问题
- 1. 这个脚本适合 tar 包,不适合所有压缩格式
- 2. 文件数量校验不是百分百严格校验
- 3. 大量小文件会非常慢
- 4. 目标磁盘状态很重要
- 十二、适用场景
- 十三、总结
一、需求说明
我的目标是:
将指定文件夹中的所有.tar文件,批量解压到另一个指定目录中。
例如:
源目录: C:\Users\1\Desktop\1 目标目录: D:\disk8假设源目录中有:
disk8_backup.tar data_001.tar data_002.tar那么脚本会自动解压为:
D:\disk8\disk8_backup\ D:\disk8\data_001\ D:\disk8\data_002\也就是说,每个.tar文件都会解压到一个与压缩包同名的文件夹中。
二、脚本功能
这个脚本主要实现了以下功能:
- 批量查找源目录中的所有
.tar文件; - 每个 tar 文件解压到独立的同名文件夹;
- 解压前检查 7-Zip 是否存在;
- 检查源目录、目标盘符、目标目录是否可用;
- 统计 tar 包内部文件数量;
- 统计目标目录中已经存在的文件数量;
- 如果目标文件数量已经满足要求,则跳过解压;
- 如果已经存在完成标记
_extract_done.flag,则直接跳过; - 如果目标目录文件数量不足,则继续解压;
- 解压成功后写入完成标记;
- 最后输出成功、失败、跳过、重新解压的统计结果。
三、为什么使用 7-Zip
这里之所以选择使用 7-Zip,而不是直接使用 Windows 自带的解压方式,主要有几个原因。
1. 7-Zip 支持命令行调用
这个脚本需要通过.bat批处理自动执行解压任务,因此需要一个可以在命令行中调用的解压工具。
7-Zip 安装后会提供7z.exe,可以直接在 BAT 脚本中使用,例如:
"C:\Program Files\7-Zip\7z.exe" x "xxx.tar" -o"目标目录"这样就可以实现自动化批量解压,而不需要手动右键解压每一个文件。
2. 方便读取 tar 包内部文件列表
脚本中不仅要解压 tar 文件,还需要先统计 tar 包内部有多少个文件。
7-Zip 可以通过下面的命令列出压缩包内部内容:
"%SEVENZIP_PATH%" l -slt "xxx.tar"其中:
l表示列出压缩包内容;-slt表示以更详细、更适合脚本解析的方式输出文件信息。
脚本正是利用这个功能,统计 tar 包内部的文件数量,再和目标目录中已经解压出来的文件数量进行对比。
3. 支持跳过已存在文件,适合断点续解压
脚本中实际使用的解压命令是:
"%SEVENZIP_PATH%" x "%%i" -aos -o"!OUT!"其中-aos的作用是:
Skip extracting of existing files也就是跳过已经存在的文件。
这对我的场景非常重要。因为我的数据里有大量几 KB 的小文件,如果解压中途失败或被迫中断,下次重新运行脚本时,不希望已经解压过的文件再被覆盖一遍。
使用-aos后,脚本可以在已有文件的基础上继续解压缺失文件,效果上类似“断点续解压”。
4. 对 tar 文件支持比较稳定
.tar本质上是一种归档格式,经常用于打包大量文件。
在 Windows 环境下,直接处理.tar文件有时不如 7-Zip 直观。
7-Zip 对.tar、.zip、.7z等常见压缩或归档格式支持较好,命令行参数也比较清晰,因此比较适合写进批处理脚本中。
5. 适合处理大量小文件场景
我这次整理的数据不是几个大文件,而是非常多几 KB 的.txt小文件。
在这种情况下,手动解压和手动检查都非常不现实。
使用 7-Zip 配合 BAT 脚本,可以做到:
- 批量处理多个 tar 包;
- 自动创建输出目录;
- 自动统计 tar 内部文件数量;
- 自动判断是否需要继续解压;
- 自动跳过已存在文件;
- 解压完成后写入标记文件。
四、完整 BAT 脚本
下面是完整脚本,可以保存为:
unzip_tar.bat然后双击运行,或者在 CMD 中运行。
@echo off setlocal enabledelayedexpansion chcp 936 >nul mode con: cols=120 lines=30 color 07 :: ============================================== :: 固定路径 :: ============================================== set "SEVENZIP_PATH=C:\Program Files\7-Zip\7z.exe" set "SRC_DIR=C:\Users\1\Desktop\1" set "DEST_DIR=D:\disk8" :: ============================================== set "TAR_LIST_FILE=%SRC_DIR%\_tar_list_temp.txt" set "DEST_DRIVE=%DEST_DIR:~0,3%" echo. echo ============================================== echo 批量解压TAR文件 - 文件数量校验版 echo ============================================== echo 源目录 : %SRC_DIR% echo 目标根目录 : %DEST_DIR% echo 目标盘符 : %DEST_DRIVE% echo ============================================== echo. if not exist "%SEVENZIP_PATH%" ( echo 错误:未找到7-Zip,请检查路径: echo %SEVENZIP_PATH% pause exit /b ) if not exist "%SRC_DIR%" ( echo 错误:源目录不存在: echo %SRC_DIR% pause exit /b ) if not exist "%DEST_DRIVE%" ( echo 错误:目标盘符不存在或不可访问: echo %DEST_DRIVE% echo. echo 请先在CMD中测试: echo dir %DEST_DRIVE% echo. echo 如果该盘符不存在,请把 DEST_DIR 改成真实存在的路径。 pause exit /b ) if not exist "%DEST_DIR%" ( mkdir "%DEST_DIR%" if errorlevel 1 ( echo 错误:无法创建目标目录: echo %DEST_DIR% echo 请检查权限,或尝试以管理员身份运行。 pause exit /b ) ) if exist "%TAR_LIST_FILE%" del "%TAR_LIST_FILE%" >nul 2>&1 :: 统计tar文件总数 set "TOTAL=0" for %%f in ("%SRC_DIR%\*.tar") do ( if exist "%%f" set /a TOTAL+=1 ) if %TOTAL% equ 0 ( echo 未找到任何tar文件 pause exit /b ) echo 找到tar文件总数:%TOTAL% echo 开始检查并解压处理... echo. set "CUR=0" set "SUCCESS=0" set "FAILED=0" set "SKIPPED=0" set "REEXTRACT=0" for %%i in ("%SRC_DIR%\*.tar") do ( if exist "%%i" ( set /a CUR+=1 set /a PERCENT=CUR*100/TOTAL set "FILE=%%~nxi" set "OUT=%DEST_DIR%\%%~ni" set "DONE_FLAG=!OUT!\_extract_done.flag" set "TAR_FILE_COUNT=0" set "OUT_FILE_COUNT=0" set "OUT_FILE_COUNT_AFTER=0" set "NEED_EXTRACT=1" echo ======================================================== echo 已处理 !CUR!/%TOTAL% 进度 !PERCENT!%% echo 正在检查:!FILE! echo 解压目录:!OUT! echo ======================================================== if exist "%TAR_LIST_FILE%" del "%TAR_LIST_FILE%" >nul 2>&1 "%SEVENZIP_PATH%" l -slt "%%i" > "%TAR_LIST_FILE%" 2>nul if not exist "%TAR_LIST_FILE%" ( echo 状态:无法读取tar文件列表 set /a FAILED+=1 ) else ( for /f %%a in ('findstr /c:"Folder = -" "%TAR_LIST_FILE%" ^| find /c /v ""') do ( set "TAR_FILE_COUNT=%%a" ) if exist "!OUT!\" ( for /f %%a in ('dir /a-d /b /s "!OUT!" 2^>nul ^| find /c /v ""') do ( set "OUT_FILE_COUNT=%%a" ) ) else ( set "OUT_FILE_COUNT=0" ) echo tar内部文件数:!TAR_FILE_COUNT! echo 目标目录文件数:!OUT_FILE_COUNT! if exist "!DONE_FLAG!" ( echo 状态:已检测到完成标记,跳过 set "NEED_EXTRACT=0" set /a SKIPPED+=1 ) else ( if !TAR_FILE_COUNT! gtr 0 ( if !OUT_FILE_COUNT! geq !TAR_FILE_COUNT! ( echo 状态:目标目录文件数量已满足,判断为已解压,跳过并补写标记 if not exist "!OUT!" mkdir "!OUT!" >nul 2>&1 echo 完成时间:%date% %time% > "!DONE_FLAG!" echo 源文件:%%i >> "!DONE_FLAG!" echo 解压目录:!OUT! >> "!DONE_FLAG!" echo tar内部文件数:!TAR_FILE_COUNT! >> "!DONE_FLAG!" echo 目标目录文件数:!OUT_FILE_COUNT! >> "!DONE_FLAG!" echo 标记来源:根据文件数量校验自动补写 >> "!DONE_FLAG!" set "NEED_EXTRACT=0" set /a SKIPPED+=1 ) ) ) if "!NEED_EXTRACT!"=="1" ( if !OUT_FILE_COUNT! gtr 0 ( echo 状态:目标目录文件数量不足,重新解压 set /a REEXTRACT+=1 ) else ( echo 状态:目标目录为空或不存在,开始解压 ) if not exist "!OUT!" ( mkdir "!OUT!" >nul 2>&1 if errorlevel 1 ( echo 状态:无法创建解压目录,可能权限不足 set /a FAILED+=1 ) ) if exist "!OUT!\" ( "%SEVENZIP_PATH%" x "%%i" -aos -o"!OUT!" >nul 2>&1 if !errorlevel! equ 0 ( for /f %%a in ('dir /a-d /b /s "!OUT!" 2^>nul ^| find /c /v ""') do ( set "OUT_FILE_COUNT_AFTER=%%a" ) echo 解压后文件数:!OUT_FILE_COUNT_AFTER! if !OUT_FILE_COUNT_AFTER! geq !TAR_FILE_COUNT! ( echo 完成时间:%date% %time% > "!DONE_FLAG!" echo 源文件:%%i >> "!DONE_FLAG!" echo 解压目录:!OUT! >> "!DONE_FLAG!" echo tar内部文件数:!TAR_FILE_COUNT! >> "!DONE_FLAG!" echo 解压后文件数:!OUT_FILE_COUNT_AFTER! >> "!DONE_FLAG!" echo 标记来源:本次解压成功并通过文件数量校验 >> "!DONE_FLAG!" echo 状态:解压成功,文件数量校验通过 set /a SUCCESS+=1 ) else ( echo 状态:解压完成但文件数量不足,可能解压不完整 set /a FAILED+=1 ) ) else ( echo 状态:解压失败 set /a FAILED+=1 ) ) ) ) echo. ) ) if exist "%TAR_LIST_FILE%" del "%TAR_LIST_FILE%" >nul 2>&1 echo ============================================== echo 全部处理完成 echo ============================================== echo 总计tar文件:%TOTAL% 个 echo 本次成功解压:%SUCCESS% 个 echo 本次失败:%FAILED% 个 echo 已跳过:%SKIPPED% 个 echo 重新解压:%REEXTRACT% 个 echo 解压根目录:%DEST_DIR% echo ============================================== echo. pause五、使用前需要修改的地方
脚本最前面有三行路径需要根据自己的实际情况修改:
set "SEVENZIP_PATH=C:\Program Files\7-Zip\7z.exe" set "SRC_DIR=C:\Users\1\Desktop\1" set "DEST_DIR=D:\disk8"含义如下:
| 变量名 | 含义 |
|---|---|
SEVENZIP_PATH | 7-Zip 的程序路径 |
SRC_DIR | 存放.tar文件的源目录 |
DEST_DIR | 解压后的目标根目录 |
如果脚本提示“源目录不存在”,需要先检查SRC_DIR对应的文件夹是否真实存在。
六、脚本运行逻辑说明
1. 检查 7-Zip 是否存在
if not exist "%SEVENZIP_PATH%" ( echo 错误:未找到7-Zip,请检查路径: echo %SEVENZIP_PATH% pause exit /b )因为脚本依赖 7-Zip 进行解压,所以运行前会先判断7z.exe是否存在。
如果路径不对,脚本会直接停止。
2. 检查源目录是否存在
if not exist "%SRC_DIR%" ( echo 错误:源目录不存在: echo %SRC_DIR% pause exit /b )源目录就是存放.tar文件的文件夹。
如果这个目录不存在,脚本不会继续执行。
3. 检查目标盘符是否可访问
set "DEST_DRIVE=%DEST_DIR:~0,3%"这一句会从目标路径中截取盘符。
例如:
DEST_DIR=D:\disk8那么:
DEST_DRIVE=D:\然后脚本会检查这个盘符是否存在:
if not exist "%DEST_DRIVE%" ( echo 错误:目标盘符不存在或不可访问: echo %DEST_DRIVE% pause exit /b )这样可以避免目标盘没有挂载、移动硬盘没插好、盘符变化等问题。
4. 统计 tar 文件总数
set "TOTAL=0" for %%f in ("%SRC_DIR%\*.tar") do ( if exist "%%f" set /a TOTAL+=1 )这里会统计源目录中有多少个.tar文件。
如果一个都没有找到,会提示:
未找到任何tar文件5. 每个 tar 文件解压到同名目录
核心逻辑是:
set "OUT=%DEST_DIR%\%%~ni"其中:
%%~ni表示 tar 文件名,不包含扩展名;OUT表示最终解压目录。
例如:
C:\Users\1\Desktop\1\disk8_backup.tar会解压到:
D:\disk8\disk8_backup这样做的好处是:
不会把所有 tar 文件直接混在一个目录下,而是每个 tar 包都有单独的输出文件夹。
七、文件数量校验逻辑
这个脚本不是简单地“发现 tar 就解压”,而是先做文件数量判断。
1. 统计 tar 包内部文件数量
"%SEVENZIP_PATH%" l -slt "%%i" > "%TAR_LIST_FILE%" 2>nul这句会使用 7-Zip 列出 tar 包内部文件信息,并写入临时文件。
然后通过:
findstr /c:"Folder = -" "%TAR_LIST_FILE%" | find /c /v ""统计 tar 包内部的文件数量。
这里统计的是文件,不包含文件夹。
2. 统计目标目录已有文件数量
dir /a-d /b /s "!OUT!" 2>nul | find /c /v ""这句会递归统计目标目录中已有的文件数量。
其中:
| 参数 | 作用 |
|---|---|
/a-d | 只统计文件,不统计文件夹 |
/b | 使用简洁输出 |
/s | 递归统计子目录 |
find /c /v "" | 统计行数,也就是文件数 |
3. 判断是否需要解压
判断逻辑大致是:
如果存在 _extract_done.flag: 直接跳过 否则: 如果目标目录文件数 >= tar 内部文件数: 认为已经解压完成,跳过,并补写完成标记 否则: 执行解压也就是说,这个脚本可以处理几种情况:
| 情况 | 脚本行为 |
|---|---|
| 目标目录不存在 | 创建目录并解压 |
| 目标目录为空 | 开始解压 |
| 目标目录已有部分文件 | 继续解压 |
| 目标目录文件数量已经满足 | 跳过 |
已经存在_extract_done.flag | 跳过 |
八、关于“重新解压”的理解
脚本中有一行提示:
状态:目标目录文件数量不足,重新解压这里的“重新解压”并不是指先删除原来的文件,然后从头覆盖一遍。
因为实际解压命令是:
"%SEVENZIP_PATH%" x "%%i" -aos -o"!OUT!" >nul 2>&1其中-aos的含义是:
Skip extracting of existing files也就是跳过已经存在的文件。
所以,如果目标目录里已经有一部分文件,脚本再次运行时:
- 已经存在的文件不会被覆盖;
- 缺失的文件会继续解压;
- 可以理解为一种“续解压”。
这一点对大批量小文件非常重要,因为如果每次都从头覆盖,会非常浪费时间。
九、完成标记文件的作用
解压成功后,脚本会在目标目录中写入:
_extract_done.flag例如:
D:\disk8\disk8_backup\_extract_done.flag文件内容大概包括:
完成时间 源文件 解压目录 tar内部文件数 解压后文件数 标记来源它的作用是:
- 表示该 tar 包已经解压完成;
- 下次运行脚本时可以快速跳过;
- 方便后期排查这个目录是从哪个 tar 文件解压出来的。
十、运行效果示例
运行时会显示类似下面的信息:
============================================== 批量解压TAR文件 - 文件数量校验版 ============================================== 源目录 : C:\Users\1\Desktop\1 目标根目录 : D:\disk8 目标盘符 : D:\ ============================================== 找到tar文件总数:1 开始检查并解压处理...处理单个 tar 文件时,会显示:
======================================================== 已处理 1/1 进度 100% 正在检查:disk8_backup.tar 解压目录:D:\disk8\disk8_backup ======================================================== tar内部文件数:53540955 目标目录文件数:17576208 状态:目标目录文件数量不足,重新解压如果最后成功,会显示:
解压后文件数:53540955 状态:解压成功,文件数量校验通过全部完成后,会输出统计结果:
============================================== 全部处理完成 ============================================== 总计tar文件:1 个 本次成功解压:1 个 本次失败:0 个 已跳过:0 个 重新解压:1 个 解压根目录:D:\disk8 ==============================================十一、需要注意的问题
1. 这个脚本适合 tar 包,不适合所有压缩格式
当前脚本只会处理:
*.tar如果要处理.zip、.7z、.tar.gz,需要修改匹配规则和解压逻辑。
2. 文件数量校验不是百分百严格校验
脚本采用的是“文件数量校验”,也就是:
目标目录文件数量 >= tar 内部文件数量就认为基本解压完成。
这种方法比较快,也适合大量小文件场景。
但是它并不会逐个校验:
- 文件名是否完全一致;
- 文件大小是否完全一致;
- 文件内容是否损坏;
- 文件哈希是否一致。
所以它适合一般批量解压和断点续解压场景,但不适合对数据完整性要求极高的场景。
如果需要更严格的校验,可以进一步增加文件清单比对或哈希校验。
3. 大量小文件会非常慢
如果 tar 包中包含几千万个小文件,即使每个文件只有几 KB,统计文件数量也会非常慢。
尤其是下面这句:
dir /a-d /b /s "!OUT!" | find /c /v ""它需要递归遍历目标目录下的所有文件。
所以如果目标目录中文件数量非常多,脚本看起来可能会“卡住”,但实际上可能是在统计文件数量。
4. 目标磁盘状态很重要
如果目标硬盘存在以下问题:
- 文件系统错误;
- 坏道;
- I/O 错误;
- 磁盘碎片严重;
- 无法创建新文件夹;
- 无法写入新文件;
那么脚本可能会出现:
- 解压失败;
- 长时间无响应;
- 文件数量不足;
- 无法创建完成标记;
- 可以读文件但不能写文件。
这种情况就不是脚本本身的问题,而是磁盘或文件系统状态可能已经异常,需要优先检查硬盘。
十二、适用场景
这个脚本比较适合以下场景:
- Windows 下批量解压
.tar文件; - tar 包数量较多;
- 每个 tar 包内部文件数量很多;
- 解压过程可能中断;
- 希望重复运行脚本时自动跳过已完成任务;
- 希望尽量避免重复覆盖已有文件;
- 需要简单判断是否解压完整。
十三、总结
这次脚本的核心思路是:
批量遍历 tar 文件 → 为每个 tar 创建同名解压目录 → 统计 tar 内部文件数量 → 统计目标目录已有文件数量 → 判断是否需要解压 → 使用 7-Zip 的 -aos 参数跳过已有文件 → 解压成功后写入完成标记相比直接手动解压,这种方式的好处是:
- 可以批量处理;
- 可以断点续解压;
- 可以避免重复覆盖;
- 可以通过文件数量做一个简单校验;
- 可以重复运行脚本而不用担心所有文件从头再来。
