Unity中Try/Catch无法捕获AssetBundle.LoadFromFile异常的解决问询
解决Unity损坏AssetBundle导致的未捕获异常问题
首先明确:AssetBundle.LoadFromFile同步加载损坏的AssetBundle时,可能抛出非托管底层异常,这类异常无法被普通C# try/catch捕获,因为它来自Unity的C++底层实现。以下是两种可行的解决方案:
方案1:使用异步加载替代同步加载
异步加载API会将异常封装在加载结果中,不会直接导致程序崩溃,你可以通过检查加载状态来处理损坏的AssetBundle:
修改后的代码示例:
private IEnumerator GetFiles() { List<string> files = new List<string>(); EnumerateFiles(baseDir, ref files); foreach (string assetBundleName in files) { AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(assetBundleName); yield return request; if (request.assetBundle == null) { // 加载失败,记录日志或跳过该文件 Debug.LogError($"加载AssetBundle失败:{assetBundleName}"); continue; } try { var prefabNames = request.assetBundle.GetAllAssetNames() .ToList() .Where(s => s.ToUpper().EndsWith(".PREFAB")) .ToList(); prefabs.Add(assetBundleName, prefabNames); } catch (Exception ex) { Debug.LogError($"处理AssetBundle内容失败:{assetBundleName},错误信息:{ex.Message}"); } finally { request.assetBundle.Unload(true); } } }
注意:因为使用了异步加载,需要将GetFiles改为协程方法,在Start中通过StartCoroutine(GetFiles())调用。
方案2:加载前先做合法性预校验
在调用加载API前,先检查文件的基本合法性,过滤明显损坏的文件:
- 检查文件是否存在且大小大于0
- 读取AssetBundle的魔数(文件开头4字节,合法AB的魔数为
0x46535955)
示例校验代码:
private bool IsValidAssetBundle(string filePath) { if (!File.Exists(filePath)) return false; FileInfo fileInfo = new FileInfo(filePath); if (fileInfo.Length < 4) // AB头部至少包含4字节魔数 return false; using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { byte[] magicBytes = new byte[4]; fs.Read(magicBytes, 0, 4); uint magicNumber = BitConverter.ToUInt32(magicBytes, 0); return magicNumber == 0x46535955; } }
然后在遍历文件时先调用校验方法:
private void GetFiles() { List<string> files = new List<string>(); EnumerateFiles(baseDir, ref files); foreach (string assetBundleName in files) { if (!IsValidAssetBundle(assetBundleName)) { Debug.LogError($"无效的AssetBundle文件:{assetBundleName}"); continue; } try { assetBundle = AssetBundle.LoadFromFile(assetBundleName); if (assetBundle == null) { Debug.LogError($"加载AssetBundle失败:{assetBundleName}"); continue; } var prefabNames = assetBundle.GetAllAssetNames() .ToList() .Where(s => s.ToUpper().EndsWith(".PREFAB")) .ToList(); prefabs.Add(assetBundleName, prefabNames); } catch (Exception ex) { Debug.LogError($"处理AssetBundle出错:{assetBundleName},错误:{ex.Message}"); } finally { if (assetBundle != null) assetBundle.Unload(true); } } }
补充说明
- 优先推荐方案1,异步加载不仅能避免崩溃,还不会阻塞主线程,提升程序运行流畅度。
- 方案2的预校验只能过滤明显损坏的文件,对于头部正常但内容损坏的AB,仍需结合异常捕获或加载结果检查处理。
内容的提问来源于stack exchange,提问作者Lord Ashes
相关产品推荐
相关产品推荐

