资讯动态

Windows Bat脚本实战:Laya小游戏一键打包与zip压缩

发布时间:2026/10/20 7:59:11 来源:尧图企业网站定制
做Laya小游戏开发最烦的往往不是业务逻辑本身而是提测前那一堆重复操作。改版本号、清缓存、把release目录拖成zip包、给压缩包起带日期的名字、再复制到专门的发布目录……手动来一遍少说十分钟手一抖还能漏掉某个资源目录。后来我把整套流程交给了Bat脚本双击一下自动执行构建、压缩、备份、清理旧包全程不用管而且换了机器、换了人跑出来的结果都一样。这篇就以Laya项目为背景完整拆一遍Windows环境下Cmd/Bat脚本的入门写法重点放在zip/unzip压缩解压的几种靠谱方案上最后给一个真实项目里一直在用的打包脚本改几个路径就能直接用。适合Windows下做Laya/H5开发、想把重复劳动固化成脚本的朋友也适合完全没写过批处理、但想快速上手的初学者。1. 先把思路理清楚Bat脚本在Laya项目里到底解决什么问题1.1 开发流程里那些“不得不做”的重复劳动在Laya项目里构建产物通常在release目录下里面包含index.html、js代码、图片音频等各种资源。提测、发版、给渠道包几乎都要把整个目录打成zip。手动的坏处不只是慢还有一致性差今天记得清掉了某张临时图明天忘了包就莫名其妙变大了今天包名叫v1.2_final明天叫v1.2_final2_真_final测试根本分不清哪个新。脚本不会这样名字、目录、步骤全是固定的人只需要双击一次。光说打包其实还低估了脚本的价值。开发过程里还有一堆“顺手做一下”的事资源目录里残留的临时文件需要定期清理几十个音频要统一转格式渠道包要按渠道名批量改名本地多个备份占了几十个G却不知道哪些该留。这些活儿全都能用Bat脚本串起来。尤其是Laya这种偏向H5/小游戏的引擎资源目录结构相对固定文件数量又多手动操作又慢又容易错脚本化是性价比最高的解法。1.2 脚本化对团队协作的隐性价值新人接手项目时口头教“你先把bin目录备份一下然后打开构建工具再把release打个包放到共享盘”……十个人能做出十种结果打包格式不统一后面接自动构建的时候非常难受。我在项目里放了一个pack.bat之后新人只需要跑一次输出的zip在固定目录、固定命名出问题看日志也很清晰。这种“把流程固化到工具里”的做法比写一页又一页的文档省心得多。另一个容易被忽略的点是脚本能够强制统一环境。有的机器上装了7-Zip有的没装手动打包时压缩率、格式都可能不一样。我把压缩方案写成脚本里固定的命令之后不管在哪台机器上跑压缩工具和参数都是一致的产出的包完全一样。这对后面接入CI/CD、做定时的自动构建都有直接好处。Bat脚本看着原始但它是Windows环境里最通用、零依赖的自动化载体。2. Bat脚本入门高频语法与编码细节一次讲透2.1 最小可用脚本与执行逻辑先看一个最基本的脚本长什么样echo off set PROJECT_NAMELayaDemo echo 当前项目: %PROJECT_NAME% echo 当前目录: %CD% pauseecho off的作用是关闭命令回显不然cmd会先把这一行命令本身打出来再输出执行结果满屏乱糟糟的看着非常难受。set用来定义变量取用时用%变量名%包裹%CD%是一个内置变量代表当前所在目录。pause是在脚本跑完后停一下防止双击运行时窗口一闪而过这是新手调试时最常用的手段。执行逻辑上有个关键点cmd是逐行解释执行的一条命令失败了脚本并不会像编程语言那样抛异常退出而是继续往下跑。这个特性坑了很多人。比如某条删除命令失败了后面还在继续打包最后产出一个残缺的包。所以要学会用if errorlevel 1 exit /b这种写法主动检查上一条命令的返回值失败就退出后面我会在完整脚本里示范。2.2 变量、分支、循环三个高频语法Bat脚本的语法很朴素但真要写起来高频用到的其实就是三样变量、if分支、for循环。变量赋值用set上面已经见过。需要注意两点第一set 变量名值这个写法带引号能避免值前后不小心带上空格第二变量的作用域是整个脚本不像高级语言有局部变量概念所以在脚本里命名变量时尽量带上项目前缀比如PROJECT_ROOT、BUILD_DIR避免互相覆盖。if分支最常用的判断是“文件/目录是否存在”if exist D:\Work\LayaDemo\release\web ( echo release目录存在 ) else ( echo release目录不存在 )在Laya项目场景里这个判断几乎每次打包都要用release目录不存在说明构建没跑成功直接fail掉不要继续往下做无意义的压缩。for循环是Bat脚本里信息量最大的部分也最劝退新手。先用一个最常见的用法遍历目录下的某种文件。echo off setlocal enabledelayedexpansion for /r D:\Work\LayaDemo\bin %%i in (*.png) do ( set fileName%%~nxi echo 找到图片: !fileName! )解释一下/r表示递归遍历子目录%%i是循环变量在bat文件里循环变量必须用两个百分号命令行里直接敲则用一个百分号。%%~nxi的意思非常实用~n取文件名不带目录~x取扩展名合起来就是“文件名.png”。这段脚本能列出bin目录下所有png图片实际中改成别的后缀、加上复制或改名命令就是一个批量处理工具。为什么echo 找到图片: !fileName!里用的是!fileName!而不是%fileName%因为for循环体在预处理阶段就被cmd整体解析了里面的%fileName%取到的是进入循环之前的值不管循环执行多少次都是同一个旧值。解决办法就是开头的setlocal enabledelayedexpansion它开启延迟变量展开循环体内取变量改用!变量名!才能取到每次循环里新赋的值。这个坑我早期踩过很多次不是在for里套if的变量读不出来就是明明改了值外面却拿不到建议一开始就把setlocal enabledelayedexpansion写成脚本固定头部。2.3 中文不乱码的编码方案Bat脚本中文乱码几乎是每个新手都会遇到的第一个“玄学问题”。其实原因不玄就是编码不匹配。Windows CMD默认代码页是936GBK如果你的bat文件保存成了UTF-8cmd按GBK去解码中文自然就是一堆“鈥濊韓”之类的符号。反过来也一样。解决方案有两种方案一把bat文件保存为ANSI编码代码页不用动中文直接正常。这是最老派的写法兼容性最好但缺点是一旦要用到某些特殊字符或者跨语言环境还是会出问题。方案二在脚本开头写一行chcp 65001 nul把代码页切成UTF-8同时把文件保存为UTF-8注意不要带BOM。nul是把这个命令的输出丢进空设备避免屏幕上多出一行“Active code page: 65001”。这种方式我在Win10/Win11上实测很稳也是我推荐的写法。要提醒一句如果文件是带BOM的UTF-8cmd在读取第一行时可能会把BOM一起解析掉造成第一条命令报错所以存成“UTF-8无BOM”最保险。另外外部程序输出的中文如果乱码也可以用chcp 65001一并解决。最省心的做法其实是脚本里尽量少写中文文件名、路径、日志都尽量用英文这也是我在后面实战脚本里采用的做法。2.4 调试要用的三件套写Bat脚本最痛苦的是调试手段少。我的工具箱里常驻三样echo输出中间变量、pause暂停看状态、errorlevel判断上一条命令是否成功。echo off set buildDirD:\Work\LayaDemo\release\web echo 构建目录: %buildDir% if exist %buildDir% ( echo 目录存在继续执行 ) else ( echo 目录不存在准备退出 exit /b 1 )通过echo把关键路径打出来比肉眼盯着代码猜靠谱得多。pause用来让窗口停住看完结果再按任意键继续。errorlevel是上一条命令的返回值非零代表失败这个在脚本里配合exit /b可以把错误层层传递出去后面在完整脚本里我会频繁用到。还有一个隐藏技巧脚本里用echo [DEBUG] ...这样的格式输出日志看起来有层次排查问题的时候一眼能看到执行到哪一步。3. zip/unzip压缩解压四种方案横向对比与选型3.1 先别装工具PowerShell自带能力就够用做Laya打包脚本最核心的一环就是zip/unzip。很多人第一反应是去装WinRAR或者7-Zip但在Windows 10/11上其实自带的能力已经足够撑起日常流程。PowerShell提供了一对简单直接的cmdletCompress-Archive和Expand-Archive。压缩一个目录Compress-Archive -Path D:\Work\LayaDemo\release\web -DestinationPath D:\Work\BuildPackages\LayaDemo.zip解压到指定目录Expand-Archive -Path D:\Work\BuildPackages\LayaDemo.zip -DestinationPath D:\Work\Unpacked优点是真的零依赖、开箱即用。缺点我也得说清楚Compress-Archive在压缩大目录时速度偏慢而且如果目录里存在被占用或路径过长的文件容易中途报错。我自己的偏好其实是用.NET的ZipFile类。很多做脚本的人不知道PowerShell可以直接调用.NET的压缩API速度和稳定性都比原生cmdlet好还能做更多精细控制Add-Type -AssemblyName System.IO.Compression.FileSystem [System.IO.Compression.ZipFile]::CreateFromDirectory(D:\Work\LayaDemo\release\web, D:\Work\BuildPackages\LayaDemo.zip)这段我从Win7用到Win11兼容性和稳定性都实测过后面实战脚本用的就是它。3.2 很多人不知道的Windows自带tar.exe还有一个系统自带方案Windows 10 1803之后系统里就内置了tar.exe它其实是libarchive的bsdtar不只是能处理tar包还支持zip格式。打zip包只需要一行tar -a -c -f D:\Work\BuildPackages\LayaDemo.zip D:\Work\LayaDemo\release\web-a是根据输出文件的后缀自动选择压缩格式-c是创建压缩包-f指定文件。解压更简单tar -xf D:\Work\BuildPackages\LayaDemo.zip我实测下来它压缩速度比Compress-Archive明显快命令也简洁。缺点有两个一是Win10 1803之前的旧版本系统没有这个命令如果团队里还有Win7的机器就直接放弃二是它的参数和GNU tar不是完全一致习惯用Linux tar的人容易默认-z参数在Windows上写tar -z -c -f out.zip是不对的。3.3 第三方工具7-Zip压缩率和可控性拉满如果对压缩包体积特别敏感比如渠道包要限制大小、CDN流量要控制那第三方工具还得上。7-Zip的命令行工具7z.exe是业界事实标准功能最全。典型的用法7z.exe a -tzip -mx9 -r D:\Work\BuildPackages\LayaDemo.zip D:\Work\LayaDemo\release\web参数逐个说a表示添加文件到压缩包-tzip指定使用zip格式不写的话默认是7z格式渠道方未必认-mx9是最高压缩率-r递归压缩子目录。-mx9虽然会慢一些但对Laya这种以图片音频为主的资源包压缩率提升明显。7-Zip的优势还在于支持密码、分卷、多线程等高级场景。如果不想安装直接用它的绿色版项目目录里放一个7z.exe就能引用。注意32位系统和64位系统的exe要选对不然在脚本里调用时会莫名其妙报“无法定位程序输入点”。3.4 方案对比与选型建议方案系统要求压缩速度压缩率额外依赖适用场景PowerShell Compress-ArchiveWin7慢低无临时小包、快速测试PowerShell .NET ZipFileWin7中中无通用自动打包我主力推荐系统自带tar.exeWin10 1803快中无脚本简洁首选7-Zip命令行任意慢(mx9) / 快(mx1)高需安装/带绿色版对包体积敏感的渠道包我的选型逻辑很直接团队机器都是Win10/11、没有额外软件安装权限的优先用.NET ZipFile稳定、可控、跨系统通用性好想少写几行命令且系统较新的用tar.exe渠道包对体积有硬性要求时才引入7z.exe的-mx9。还要多说一句不管选哪种压缩方案脚本里一定要带一个解压验证的步骤。压缩完不解压检查一遍发出去才发现包在半路损坏或者缺文件那才是真正的灾难。这个“压缩完立刻解压验证”的思路贯穿了我后面整个实战脚本。3.5 关于zip命令的几个常见误会新手最容易有的几个误会也一并说掉。第一cmd本身没有内置的zip、unzip命令Linux上那套在Windows原生环境里不存在所以必须借助PowerShell、tar.exe或第三方工具。第二Windows右键“发送到-压缩(zipped)文件夹”只能手工操作没法在命令行直接调用不能写进自动化脚本。第三WinRAR的命令行工具Rar.exe是收费软件商业用途要注意授权问题除非公司已经买了授权否则不建议在脚本里依赖它。4. Laya实战开箱可用的一键打包发布脚本4.1 脚本要实现哪些功能把前面所有知识点串起来我按自己的实际工作流设计了一个满足下面条件的打包脚本一次双击完成全部流程校验目录 → 生成带时间戳的包名 → 清理旧包 → 打zip压缩包 → 解压验证 → 写日志只依赖Windows系统自带能力不要求安装任何第三方工具保证在任何一台Win10/11机器上“开箱可用”脚本里避免中文文件名和中文字符输出减少编码坑用%~dp0获取脚本自身所在目录日志写到脚本旁边方便查看4.2 完整脚本echo off setlocal enabledelayedexpansion chcp 65001 nul REM REM Laya project one-click package script REM Tested on Win10 / Win11 REM Modify PROJECT_ROOT and RELEASE_DIR only REM set SCRIPT_DIR%~dp0 set PROJECT_ROOTD:\Work\LayaDemo set RELEASE_DIR%PROJECT_ROOT%\release\web set OUTPUT_DIRD:\Work\BuildPackages set KEEP_OLD_PACKAGES5 set PACKAGE_PREFIXLayaDemo set LOG_FILE%SCRIPT_DIR%package_log.txt echo [INFO] Start packaging at %DATE% %TIME% echo [INFO] Log file: %LOG_FILE% REM Step 1: check release dir if not exist %RELEASE_DIR% ( echo [ERROR] Release dir not found: %RELEASE_DIR% exit /b 1 ) REM Step 2: generate timestamp via WMIC, fallback to PowerShell for /f tokens2 delims %%i in (wmic os get localdatetime /value 2^nul ^| find ) do set DT%%i if not defined DT ( for /f delims %%i in (powershell -NoProfile -Command Get-Date -Format yyyyMMdd_HHmmss) do set DT%%i ) set STAMP%DT:~0,8%_%DT:~8,6% set PACKAGE_NAME%PACKAGE_PREFIX%_%STAMP%.zip set OUTPUT_FILE%OUTPUT_DIR%\%PACKAGE_NAME% REM Step 3: ensure output dir if not exist %OUTPUT_DIR% mkdir %OUTPUT_DIR% echo [INFO] Release dir : %RELEASE_DIR% echo [INFO] Output file : %OUTPUT_FILE% REM Step 4: remove old packages, keep latest N if exist %OUTPUT_DIR% ( powershell -NoProfile -Command Get-ChildItem %OUTPUT_DIR% -Filter *.zip | Sort-Object LastWriteTime -Descending | Select-Object -Skip %KEEP_OLD_PACKAGES% | Remove-Item -Force ) REM Step 5: compress using .NET ZipFile echo [INFO] Compressing... powershell -NoProfile -Command Add-Type -AssemblyName System.IO.Compression.FileSystem; [System.IO.Compression.ZipFile]::CreateFromDirectory(%RELEASE_DIR%, %OUTPUT_FILE%) if errorlevel 1 ( echo [ERROR] Compress failed. exit /b 1 ) REM Step 6: verify zip by counting entries echo [INFO] Verifying zip... for /f delims %%i in (powershell -NoProfile -Command Add-Type -AssemblyName System.IO.Compression.FileSystem; $z[System.IO.Compression.ZipFile]::OpenRead(%OUTPUT_FILE%); $c$z.Entries.Count; $z.Dispose(); Write-Output $c) do set ENTRY_COUNT%%i echo [INFO] Packed entries: %ENTRY_COUNT% REM Step 7: write log echo %DATE% %TIME% package%PACKAGE_NAME% entries%ENTRY_COUNT% %LOG_FILE% echo [INFO] Done. Package: %OUTPUT_FILE% pause4.3 脚本逐段拆解说明开头三行是固定套路echo off关闭回显setlocal enabledelayedexpansion开启延迟变量展开chcp 65001 nul切到UTF-8代码页。这三行组合在一起基本避免了新手乱码和for循环变量读不到值这两大类问题。配置区里只有几个变量需要动。SCRIPT_DIR用%~dp0获取脚本自身所在目录这样日志文件会跟脚本放一起不管从哪个路径双击都不会写丢。PROJECT_ROOT是Laya项目根目录RELEASE_DIR是构建产物目录按自己的实际路径改掉就行。KEEP_OLD_PACKAGES设置保留最近几个版本包超过这个数量的旧包会自动清理这个参数我建议设成5左右既能回溯旧版本又不至于把磁盘堆满。Step 2是时间戳的生成。wmic os get localdatetime /value能拿到一个形如20250114153000.000000480的字符串通过tokens2 delims把后面的部分取出来再用截取语法%DT:~0,8%拿前8位当日期%DT:~8,6%拿第9到14位当时间。这里我加了一道保险如果系统里没有wmic命令新版Win11正在逐步移除它就自动改用PowerShell的Get-Date -Format yyyyMMdd_HHmmss来生成同样格式的时间戳。这样脚本在旧版、新版Windows上都能跑。Step 5是核心压缩命令。powershell -NoProfile -Command表示直接执行一段命令-NoProfile可以避免加载用户Profile拖慢速度。命令里调用.NET的ZipFile::CreateFromDirectory第一个参数是被压缩目录第二个参数是输出zip文件路径。这里有个细节路径用单引号包起来是为了防止PowerShell把\当转义符处理。bat里这行整体用的双引号内部的单引号会被原样传给PowerShell实测路径里有空格也能正常工作。Step 6是解压验证也是整个脚本里我最坚持加的一段。压缩完成后用ZipFile::OpenRead打开刚才生成的zip读取条目数然后输出。如果这个数字是0或者命令报错说明压缩包很可能有问题能直接拦截住“半成品包发出去”的事故。现实中很多压缩工具不报错但解压时才发现少文件所以验证步骤不能省。Step 4的旧包清理用了一条PowerShell管道命令把输出目录下所有zip文件按修改时间倒序排列跳过前N个也就是最新的N个其余删除。这样每次打包完目录里始终只保留最近5个版本包不用手动清理。4.4 把脚本嵌入日常工作流脚本写好后建议直接放到Laya项目根目录下命名pack.bat右键发送快捷方式到桌面。这样每天提测时双击桌面快捷方式就行不需要打开命令行、敲路径。使用上有两个小习惯可以让体验更好。第一日志文件package_log.txt会自动生成在脚本旁边建议把它加进版本管理的忽略列表里避免日志随项目提交到仓库污染代码库。第二脚本本身不调用Laya构建只负责对已有release目录打包。如果你的构建流程也固定可以在Step 1之前插入一行构建命令比如call npm run build并检查errorlevel失败就退出。这样双击一次构建和打包全自动真正做到“一条龙”。再往后可以扩展参数化比如执行pack.bat beta时把包名加上_beta前缀执行pack.bat release时去掉调试用的文件这些用%1参数加上if分支就能实现。刚开始不用做太复杂先把最痛的那条路径自动化起来后面再慢慢加功能。5. 常见问题与排查技巧实录5.1 命令失败为什么没有停下来这是Bat脚本和普通编程语言最大的思维差异。cmd默认不会因为某条命令出错就中止整个脚本后面的命令照常执行最后产出一个残缺的结果。解决办法是养成主动检查errorlevel的习惯。在我给的脚本里压缩命令后面紧跟着if errorlevel 1 exit /b 1这就是一个典型的错误防线。如果你自己写脚本凡是碰到关键步骤比如删除、复制、压缩都要加一个类似的检查。5.2 中文乱码到底怎么排查乱码问题可以从三个方向逐一排查现象可能原因解决办法bat脚本里的中文输出乱码文件编码和代码页不匹配文件存为UTF-8无BOM脚本开头加chcp 65001 nul外部命令输出乱码程序输出编码和当前代码页不一致同样先切代码页再执行命令中文文件名在压缩包里乱码压缩时编码处理不一致路径和文件名尽量用英文或在压缩命令中指定字符集早期我贪图省事直接用默认编码保存结果脚本在同事机器上跑出来一堆乱码排查了半天才发现是文件存成了带BOM的UTF-8。现在一律用“UTF-8无BOM chcp 65001”的组合再也没出过问题。5.3 路径带空格和长路径怎么办路径带空格是脚本里最普遍的坑。写set变量时用set PROJECT_ROOTD:\Work\LayaDemo这种带引号的写法使用变量时也带上引号if not exist %RELEASE_DIR%。不光是bat自己传给PowerShell的路径也最好用单引号包一层两边都处理好空格就影响不到你。长路径则是另一个老生常谈。Windows传统路径上限是260个字符Laya项目的node_modules一旦被卷进来动不动就超。我踩过的其中一个坑就是项目里有node_modules压缩时路径太长直接爆掉。解决办法有几种压缩前把node_modules排除使用\\?\长路径前缀或者用subst命令把长目录映射成一个临时盘符。实战里最省心的做法就是把需要打包的内容先同步到一个结构简单的临时目录再从那个短目录去压缩。5.4 for循环里变量怎么又读不到新值这个问题我在第2章提到过但是要多说几遍因为它太容易踩了。核心就是for循环体整体在预处理阶段就被解析%var%在循环开始前就取好值了不会随循环更新。加setlocal enabledelayedexpansion、循环内改成!var!这两个条件缺一不可。没有开启延迟变量展开时直接写!var!cmd不会报错但变量压根解析不出来等于没写。举个具体场景在for循环里用set flag1做标记循环外判断flag。如果不用!flag!循环外那层永远读到的可能是循环前的旧值逻辑完全不对。建议写任何带for的脚本时第一行就固定加上setlocal enabledelayedexpansion不要等到出bug了再回头补。5.5 压缩包损坏或解压失败的原因压缩这一步本身其实很少出错更多是环境在捣乱。文件被占用是最常见的情况比如某个资源文件正被浏览器或者编辑器的进程开着压缩工具读不全就打出个残缺包。其次是杀毒软件尤其是在压缩大量文件时安全软件会同时扫描这些文件偶发性地锁住文件导致压缩失败。还有一个容易被忽略的点如果输出目录在网络磁盘上网络抖动也可能让写入的文件不完整。所以我在脚本里坚持加解压验证就是为了把这些偶发问题兜住。验证时除了数条目数还可以再抽查几个关键的入口文件是否存在比如index.html、game.js。这些文件在不在基本就能判断包是不是完整可用。5.6 实用问题速查表问题常见原因快速解法双击bat窗口一闪而过脚本没有pause或执行错误最后加pause用cmd /k 打开窗口保留现场chcp 65001后中文更乱文件本身是ANSI编码文件另存为UTF-8无BOM压缩包体积异常大把node_modules或临时目录打进去了排除无关目录后再压缩清理旧包时把新包也删了排序或Skip参数写错先Sort最后写入时间倒序再Select-Object -Skip N脚本在部分机器上跑不起来系统版本差异缺命令用PowerShell兜底wmic和tar都做fallback打包过程中被杀毒拦截安全软件对批量文件操作敏感压缩临时目录设为白名单最后再分享一个我做这套脚本时的个人体会。最早写它我也只是为了少点几次鼠标但结果远不止省事现在每次提测双击一下日志里能看到打出来的包名、条目数、大小心里特别踏实。中间踩过的坑乱码、变量延迟、路径空格、杀毒软件干扰几乎都和上面这篇写的内容对应。如果你打算照着搭一套建议先拿一个测试目录跑通了再上正式工程改路径时看清楚有没有写错剩下的就交给脚本去重复劳动吧。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑