# 路径助手

  • 分平台处理 StreamingAssets 路径
  • Application.streamingAssetsPath 会根据不同的平台返回对应的 StreamingAssets 目录,这是最常用的方法,也可以使用 Unity 宏标签手动分平台,在下面的代码中会做出演示。
  • 只有 PC 端的 StreamingAssets 文件夹是可读写的,其他平台都是只读的(.txt 文件可以直接读,其他类型的文件需要进一步操作)。
    • 移动端(Android、iOS 等):想要读写这些文件,需要将 StreamingAssets 文件夹中的内容拷贝到持久化路径 Application.persistentDataPath(Unity 外部目录),这个路径可以在运行时进行读写操作。
    • Web 端:无法写入。
  • 注意:如果 StreamingAssets 下的文件很多,应该单独处理他们(例:在第一次进入游戏时完成文件的复制、在游戏的加载场景(过渡场景、动画等)中完成文件的复制)

按需加载

using System;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
namespace Common
{
    /// <summary>
    /// 路径助手(按需加载)
    /// </summary>
    public class PathHelper
    {
        /// <summary>
        /// 手动分平台处理 StreamingAssets 路径
        /// </summary>
        /// <param name="path">StreamingAssets 中的路径 & lt;/param>
        /// <returns></returns>
        [Obsolete("Use GetPath instead", true)]
        public static string HandlePath(string path)
        {
            string localPath;
            #region 分平台判断路径
            // 这样写 性能不好
            //if (Application.platform == RuntimePlatform.Android)
            //{
            //    localPath = Application.streamingAssetsPath + "/" + path;
            //}
            //else
            //{
            //    localPath = "file://" + Application.streamingAssetsPath + "/" + path;
            //}
            // 性能更高的写法,使用 Unity 宏标签
            // 不同的平台会拥有不同的代码(如果发布到安卓平台,就只有第三段代码,其他的代码不会打包带走)
            //Application.dataPath 会定位到 Assets 目录
            //Application.streamingAssetsPath 会根据不同的平台返回对应的 StreamingAssets 目录,一般情况下使用这个即可
#if UNITY_EDITOR || UNITY_STANDALONE
            localPath = "file://" + Application.dataPath + "/StreamingAssets/" + path;
#elif UNITY_IOS
            localPath = "file://" + Application.dataPath + "/Raw/" + path;
#elif UNITY_ANDROID
            localPath = "jar:file://" + Application.dataPath + "!/assets/" + path;
#else
            localPath = "file://" + Application.streamingAssetsPath + "/" + path;
#endif
            #endregion
            return localPath;
        }
        /// <summary>
        /// 分平台处理 StreamingAssets 路径
        /// </summary>
        /// <param name="path">StreamingAssets 中的路径 & lt;/param>
        /// <returns></returns>
        public static string GetPath(string path)
        {
#if UNITY_ANDROID || UNITY_IOS
            string resPath = Application.persistentDataPath + path;
            if (!File.Exists(resPath))
            {
                CopyFile(path);
            }
            return resPath;
#else
            return Application.streamingAssetsPath + path;
#endif
        }
        /// <summary>
        /// 将 StreamingAssets 中的文件拷贝到持久化路径中 path=StreamingAssets 中的路径
        /// </summary>
        private static void CopyFile(string path)
        {
            // 获取 StreamingAssets 路径
            // 创建 UnityWebRequest 对象
            UnityWebRequest www = UnityWebRequest.Get(Application.streamingAssetsPath + path);
            // 发送请求并等待返回
            // 如果不是静态方法,可以使用协程,但是协程会影响其他方法的调用,所以不建议使用
            //yield return www.SendWebRequest();
            www.SendWebRequest();
            while (!www.isDone) { }
            if (www.result != UnityWebRequest.Result.Success)
            {
                Debug.LogError("拷贝文件出错:" + www.error);
            }
            else
            {
                // 创建路径(如果不存在)
                Directory.CreateDirectory(Application.persistentDataPath + path.Substring(path.IndexOf('/'), path.LastIndexOf('/')));
                // 写入文件
                File.WriteAllBytes(Application.persistentDataPath + path, www.downloadHandler.data);
            }
        }
    }
}

优先全部加载(单例模式)

using System.Collections;
using System.IO;
using System.Linq;
using UnityEngine;
using UnityEngine.Networking;
namespace Common
{
    /// <summary>
    /// 路径助手(优先全部加载)
    /// </summary>
    public class PathHelperPriority : MonoSingleton<PathHelperPriority>
    {
        protected override void Init()
        {
            base.Init();
#if UNITY_ANDROID || UNITY_IOS
            StartCoroutine(GetFilePath());
#else
            return;
#endif
        }
        /// <summary>
        /// 分平台处理 StreamingAssets 路径
        /// </summary>
        /// <param name="path">StreamingAssets 中的路径 & lt;/param>
        /// <returns></returns>
        public string GetPath(string path)
        {
#if UNITY_ANDROID || UNITY_IOS
            return Application.persistentDataPath + path;
#else
            return Application.streamingAssetsPath + path;
#endif
        }
        /// <summary>
        /// 获取 StreamingAssets 中所有文件路径
        /// </summary>
        private IEnumerator GetFilePath()
        {
            string sourcePath = Application.streamingAssetsPath;
            string destinationPath = Application.persistentDataPath;
            // 选取需要拷贝的文件
            string[] filePaths = Directory.GetFiles(sourcePath, "*", SearchOption.AllDirectories).
                Where(
                    file => file.EndsWith(".txt") ||
                    file.EndsWith(".xml") ||
                    file.EndsWith(".db")).
                ToArray();
            foreach (string filePath in filePaths)
            {
                string relativePath = filePath.Substring(sourcePath.Length).Replace("\\", "/");
                string destFilePath = destinationPath + relativePath;
                // 如果文件已存在,则跳过
                if (File.Exists(destFilePath)) continue;
                yield return CopyFile(relativePath);
            }
        }
        /// <summary>
        /// 将 StreamingAssets 中的文件拷贝到持久化路径中 path=StreamingAssets 中的路径
        /// </summary>
        private IEnumerator CopyFile(string path)
        {
            // 获取 StreamingAssets 路径
            // 创建 UnityWebRequest 对象
            UnityWebRequest www = UnityWebRequest.Get(Application.streamingAssetsPath + path);
            // 发送请求并等待返回
            yield return www.SendWebRequest();
            if (www.result != UnityWebRequest.Result.Success)
            {
                Debug.LogError("拷贝文件出错:" + www.error);
            }
            else
            {
                // 创建路径(如果不存在)
                Directory.CreateDirectory(Application.persistentDataPath + path.Substring(path.IndexOf('/'), path.LastIndexOf('/')));
                // 写入文件
                File.WriteAllBytes(Application.persistentDataPath + path, www.downloadHandler.data);
            }
        }
    }
}