使用Mono.Cecil补丁Unity自定义脚本时遭遇IOException异常求助
解决Mono.Cecil操作Unity程序集时的IOException: Win32 IO returned 12异常
这个IOException(错误码12)我之前在给Unity项目做Cecil补丁的时候也碰到过,核心原因基本都是目标程序集文件被系统或Unity锁定了——Unity在运行时会持续加载项目中的脚本程序集,这时候直接读写原文件肯定会触发文件占用的报错。下面给你几个实用的解决思路:
1. 先操作临时文件再替换原程序集
不要直接修改Unity正在使用的原文件,先把它复制到临时目录做补丁,完成后再替换原文件(替换前务必确保Unity没有锁定原文件,比如先关闭Unity编辑器,或者在Unity未启动时执行补丁)。示例代码如下:
using System.IO; using Mono.Cecil; string originalAssemblyPath = assembly.Location; string tempAssemblyPath = Path.Combine(Path.GetTempPath(), Path.GetFileName(originalAssemblyPath)); // 复制原文件到临时路径 File.Copy(originalAssemblyPath, tempAssemblyPath, overwrite: true); // 在临时文件上执行补丁 using (AssemblyDefinition assemblyDef = AssemblyDefinition.ReadAssembly(tempAssemblyPath)) { // 这里写你的补丁逻辑,比如注入代码到MonoBehaviour子类 assemblyDef.Write(); } // 替换原文件(确保此时Unity未加载该程序集) File.Copy(tempAssemblyPath, originalAssemblyPath, overwrite: true); File.Delete(tempAssemblyPath);
2. 避开Unity的程序集锁定时机
如果要在Unity编辑器内执行补丁,一定要避开Unity加载程序集的时段:
- 可以在Unity启动前运行补丁工具;
- 借助Unity的
AssemblyReloadEvents,在程序集即将重新加载的时机触发补丁(注意要避免无限循环触发重载); - 操作前调用
AssetDatabase.Refresh()确保文件状态同步,不过这一步不一定能解除锁定,还是优先用临时文件方案。
3. 优化Cecil的读写参数
有时候参数配置不当也会导致文件操作异常,比如不必要的符号文件读取会增加资源占用,建议调整Reader和Writer参数:
var readerParams = new ReaderParameters { ReadSymbols = false, // 不需要调试符号的话关闭,减少IO操作 ReadWrite = false, // 临时文件不需要ReadWrite,后续写入时直接覆盖即可 }; using (AssemblyDefinition assemblyDef = AssemblyDefinition.ReadAssembly(tempAssemblyPath, readerParams)) { // 补丁逻辑... var writerParams = new WriterParameters { WriteSymbols = false, SymbolWriterProvider = null }; assemblyDef.Write(writerParams); }
4. 排查文件权限问题
错误码12偶尔也会和文件权限有关,比如Unity项目的Library/ScriptAssemblies目录可能需要管理员权限才能修改。可以尝试以管理员身份运行你的补丁工具,或者检查目标目录的读写权限设置。
内容的提问来源于stack exchange,提问作者Mor Zilberman




