在 Unity 开发中,StreamingAssets
是一个常用的文件夹,用来存放需要打包到应用程序中的静态文件。但在某些情况下(动态文件的更新和修改,需要读写等),为了支持文件动态读取或修改,资源需要从 StreamingAssets
复制到 PersistentDataPath
,再进行加载。
比如我现在是需要将一个电脑端的数字人加载项目放到AR眼镜中,单纯从 StreamingAssets
中读取资源在眼镜中无法正常显示,但复制到 PersistentDataPath
再动态加载就可以成功显示。
本文将详细介绍如何在执行资源加载之前,将 StreamingAssets
的资源复制到 PersistentDataPath
并正确加载这些资源。本文主要内容包括以下几个部分:
- Unity 路径简介:
StreamingAssets
和PersistentDataPath
的区别。 - 核心实现步骤:如何在调用资源加载逻辑之前完成复制。
- 完整代码示例:实际场景下的完整实现代码。
1. Unity 路径简介
StreamingAssets
文件夹
- 作用:用于存放静态资源文件,资源会被原封不动地打包到应用程序中。
- 访问方式:
- PC 平台:通过
Application.streamingAssetsPath
获取路径,可直接访问文件。 - Android 平台:由于资源被打包在 APK 中,无法直接访问,需使用
UnityWebRequest
或其他方式读取。
- PC 平台:通过
PersistentDataPath
文件夹
- 作用:用于存储动态生成的文件或需要持久化的文件(例如保存文件、日志等)。
- 访问方式:通过
Application.persistentDataPath
获取路径,可直接读取和写入文件。
2. 核心实现步骤
在调用资源加载逻辑之前,首先需要确保资源已被复制到 PersistentDataPath
,并将资源路径更新为新路径。以下是核心步骤:
- 复制资源:遍历资源路径,将资源从
StreamingAssets
复制到PersistentDataPath
。 - 更新路径:将资源路径替换为指向
PersistentDataPath
的新路径。 - 加载资源:调用加载逻辑时使用更新后的路径。
3. 实现代码
以下是简化的实现代码,用于展示核心逻辑。
主函数
private mainFunction()
{
// 获取资源路径
var basePath = GetBasePath();
// 定义资源路径
//PostResult是自定义的类
var meta = new PostResult
{
upload_zzz_url = $"{
basePath}/zzz.fbx",
upload_yyy_url = $"{
basePath}/yyy.png",
upload_xxx_url = new[] {
$"{
basePath}/xxx1.fbx", $"{
basePath}/xxx2.fbx" }
};
// 1. 复制资源到 PersistentDataPath
await CopyAllResourcesToPersistentDataPath(meta);
// 2. 更新路径为 PersistentDataPath
UpdateMetaPathsToPersistent(meta);
// 3. 加载资源
//实现Load()加载资源的代码
}
步骤 1:复制所有资源到 PersistentDataPath
实现一个方法,将资源路径从 StreamingAssets
复制到 PersistentDataPath
。以下为伪代码:
private async UniTask CopyAllResourcesToPersistentDataPath(PostResult meta)
{
// 定义一个列表来存储所有路径
List<string> allPaths = new List<string>
{
meta.upload_zzz_url,
meta.upload_yyy_url
};
allPaths.AddRange(meta.upload_xxx_url);
// 遍历所有路径并逐一复制
foreach (var path in meta.AllPaths)
{
await CopyToPersistentDataPath(path);
}
}
private async UniTask CopyToPersistentDataPath(string sourcePath)
{
// 目标路径
string persistentPath = GetPersistentPath(sourcePath);
// 如果文件已存在,跳过
if (FileExists(persistentPath)) return;
// 判断平台
if (Application.platform == RuntimePlatform.Android && !sourcePath.Contains("://"))
{
sourcePath = $"file://{
sourcePath}"; // Android 平台需要添加前缀
}
// 使用 UnityWebRequest 从 StreamingAssets 读取文件
using (UnityWebRequest request = UnityWebRequest.Get(sourcePath))
{
await request.SendWebRequest();
if (request.result == UnityWebRequest.Result.Success)
{
// 将文件写入到 PersistentDataPath
File.WriteAllBytes(persistentPath, request.downloadHandler.data);
}
else
{
Debug.LogError($"Failed to copy file from {
sourcePath} to {
persistentPath}: {
request.error}");
}
}
}
步骤 2:更新资源路径为 PersistentDataPath
复制完成后,需要更新资源路径为指向 PersistentDataPath
。
private void UpdateMetaPathsToPersistent(PostResult meta)
{
// 更新单个路径
meta.upload_zzz_url = UpdatePathToPersistent(meta.upload_zzz_url);
// 更新数组路径
meta.upload_xxx_url = meta.upload_xxx_url.Select(UpdatePathToPersistent).ToArray();
}
private string UpdatePathToPersistent(string sourcePath)
{
string fileName = Path.GetFileName(sourcePath);
return Path.Combine(Application.persistentDataPath, fileName);
}