You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

使用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

火山引擎 最新活动