填补Resources和WWW加载本地资源的坑

时间:2023-12-13 18:13:20

总的来说Resources和WWW加载本地资源坑比较多,大多与路径有关。

下面代码构成了一个路径的预读模块:

此模块主要解决的坑是:Resources或WWW加载本地的文件夹中的多个文件时,无法获取文件夹下的文件名称的坑,原因是Resources路径和StreamingAssets路径下打包到安卓安装后路径都不再存在的问题。想要读取Resources路径或StreamingAssets路径某个文件夹下的大量文件,找了好久都没找到方法。后来想了一个绕过此坑的办法,就是在程序未执行前先保存一份路径信息到场景中或保存成预设,运行时就可以访问了。

代码1.多叉树实现目录结构

using System;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 使用多叉树实现目录结构
/// </summary>
[Serializable]
public class PathStruct
{
/// <summary>
/// 目录名称或文件名称(不包含扩展名)
/// </summary>
public string name;
/// <summary>
/// 扩展名都是以“.”开头的
/// </summary>
public string extensionName;
/// <summary>
/// 是否是文件
/// </summary>
public bool isFile;
/// <summary>
/// 父节点
/// </summary>
[NonSerialized]
public PathStruct parent;
/// <summary>
/// 子节点
/// </summary>
public List<PathStruct> children = new List<PathStruct>();

/// <summary>
/// 文件夹结构构造函数
/// </summary>
/// <param name="name"></param>
/// <param name="parent"></param>
/// <param name="children"></param>
public PathStruct(string name, PathStruct parent, List<PathStruct> children = null)
{
this.name = name;
this.parent = parent;
this.children = children;
if (parent != null)
parent.AddChild(this);
if (children == null)
this.children = new List<PathStruct>();
}
/// <summary>
/// 文件结构构造函数
/// </summary>
/// <param name="name"></param>
/// <param name="parent"></param>
/// <param name="extensionName"></param>
public PathStruct(string name, PathStruct parent, string extensionName)
{
this.name = name;
this.parent = parent;
this.extensionName = extensionName;
isFile = true;
if (parent != null)
parent.AddChild(this);
if (children == null)
children = new List<PathStruct>();
}

/// <summary>
/// 放回从父物体到此物体的完整路径,物体间用'/'隔开
/// </summary>
/// <returns></returns>
public override string ToString()
{
if (parent == null || string.IsNullOrEmpty(parent.name))
return name;
return parent +"/"+ name;
}
/// <summary>
/// 输出从根节点到此节点的完整路径(相对完整,并不是绝对路径)
/// </summary>
/// <param name="isContainsExtension">是否包括文件扩展名</param>
/// <returns></returns>
public string ToString(bool isContainsExtension)
{
if(isContainsExtension)
return parent + "/" + name+extensionName;
return ToString();
}
/// <summary>
/// 增加子节点
/// </summary>
/// <param name="pathStruct"></param>
public void AddChild(PathStruct pathStruct)
{
children.Add(pathStruct);
pathStruct.parent = this;
}

/// <summary>
/// 增加子节点
/// </summary>
/// <param name="pathStruct"></param>
public void AddChildren(List<PathStruct> pathStructs)
{
children.AddRange(pathStructs);
foreach (var pathStruct in pathStructs)
{
pathStruct.parent = this;
}
}
/// <summary>
/// 获取该节点下所有子节点的完整路径(相对完整,并不是绝对路径)
/// </summary>
/// <param name="isContainsExtension"></param>
/// <returns></returns>
public List<string> GetChildrenFullPath(bool isContainsExtension)
{
if (children == null || children.Count == 0) return null;
var res = new List<string>(children.Count);
foreach (var pathStruct in children)
{
if (pathStruct.name != null)
{
res.Add(pathStruct.ToString(isContainsExtension));
}
}
return res;
}

/// <summary>
/// 获取该节点下所有子节点的名称(相对完整,并不是绝对路径)
/// </summary>
/// <param name="isContainsExtension"></param>
/// <returns></returns>
public List<string> GetChildrenNames(bool isContainsExtension)
{
if (children == null) return null;
var res = new List<string>(children.Count);
foreach (var pathStruct in children)
{
if (pathStruct.name != null)
{
res.Add(pathStruct.name + (isContainsExtension?extensionName:""));
}
}
return res;
}
/// <summary>
/// 打印出该节点下所有节点
/// </summary>
/// <param name="isFullPath"></param>
/// <param name="isContainsExtension"></param>
public void PrintAll(bool isFullPath = false ,bool isContainsExtension = false)
{
if(isFullPath)
Debug.Log(ToString(isContainsExtension));
else
Debug.Log(name);
if (children != null)
{
foreach (var pathStruct in children)
{
pathStruct.PrintAll(isFullPath, isContainsExtension);
}
}
}
/// <summary>
/// 在子节点中查找符合条件的节点
/// </summary>
/// <param name="condition"></param>
/// <param name="isFindChild"></param>
/// <returns></returns>
public PathStruct Find(Func<PathStruct,bool> condition,bool isFindChild = false)
{
if (children == null) return null;
foreach (var pathStruct in children)
{
if (condition(pathStruct))
return pathStruct;
if (isFindChild)
{
var pathS = pathStruct.Find(condition, isFindChild);
if (pathS != null)
return pathS;
}
}
return null;
}
/// <summary>
/// 在子节点中查找符合条件的节点
/// </summary>
/// <param name="condition"></param>
/// <param name="isFindChild"></param>
/// <returns></returns>
public List<PathStruct> FindAll(Func<PathStruct, bool> condition, bool isFindChild = false)
{
if (children == null) return null;
var res = new List<PathStruct>();
foreach (var pathStruct in children)
{
if (condition(pathStruct))
res.Add( pathStruct);
if (isFindChild)
{
var pathSS = pathStruct.FindAll(condition, isFindChild);
if (pathSS != null)
res.AddRange( pathSS);
}
}
return res;
}
/// <summary>
/// 重新根据子节点信息给各节点装入父节点信息
/// </summary>
public void ResetParent()
{
if (children != null)
foreach (var pathStruct in children)
{
pathStruct.parent = this;
pathStruct.ResetParent();
}
}
}

代码2. 运行在Editor模式下的菜单命令,此代码应该存放在某个Editor目录下

using CommonUtilities;
using UnityEditor;
using UnityEngine;

public class PathStructionBuilder
{
[MenuItem("Path/Create Resouces Path Info To Current Scene")]
static void CreateGObyResources()
{
var resourcesPath = Application.dataPath + "/Resources/";
Debug.Log("resourcesPath: "+ resourcesPath);
ResourcesPathAccess.Instance.root = new PathStruct("",null);
CreatePathStruct(resourcesPath, ResourcesPathAccess.Instance.root);

ResourcesPathAccess.Instance.root.PrintAll(true);
}

[MenuItem("Path/Create StreamingAssets Path Info To Current Scene")]
static void CreateGObyStreamingAssets()
{
var streamingAssets = Application.dataPath + "/StreamingAssets/";
Debug.Log("StreamingAssets: " + streamingAssets);
StreamingAssetAccess.Instance.root = new PathStruct("", null);
CreatePathStruct(streamingAssets, StreamingAssetAccess.Instance.root);

StreamingAssetAccess.Instance.root.PrintAll(true);
}

public static void CreatePathStruct(string path,PathStruct parent)
{
var files = FileHelper.GetFileNames(path);
foreach (var p in files)
{
if (p.Contains(".meta"))
continue;
new PathStruct(GetPathName(p), parent, GetFileExtensionName(p));
Debug.Log("增加文件: " + p);
}
var paths = FileHelper.GetDirectories(path);
foreach (var p in paths)
{
var pathStruct = new PathStruct(GetPathName(p), parent);
Debug.Log("增加路径: " + p);
CreatePathStruct(p, pathStruct);
}

}

private static string GetFileExtensionName(string pathName)
{
return FileHelper.GetExtension(pathName);
}

public static string GetPathName(string path)
{
return FileHelper.GetFileNameNoExtension(path);
}

}

代码3. Resources路径下的信息保存位置

using System;
using System.Collections.Generic;
using UnityEngine;

public class ResourcesPathAccess:SingleBhv<ResourcesPathAccess>
{
public PathStruct root;

public override void Init()
{
base.Init();
root.ResetParent();
}

public List<string> GetFileList(string resourceUri)
{
if (!isInited)
Init();
var ss = resourceUri.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
var pathStruct = root;
foreach (var s in ss)
{
if (pathStruct != null)
pathStruct = pathStruct.Find(t => t.name == s);
else
Debug.LogError("resourceUri 错误!");
}
if (pathStruct != null)
{
return pathStruct.GetChildrenFullPath(false);
}
return null;
}
}

代码4. StreamingAssets路径下的信息保存位置

using System;
using System.Collections.Generic;
using UnityEngine;

public class StreamingAssetAccess : SingleBhv<StreamingAssetAccess>
{
public PathStruct root;
public override void Init()
{
base.Init();
root.ResetParent();
}

public List<string> GetFileList(string resourceUri)
{
if(!isInited)
Init();
var ss = resourceUri.Split(new []{'/'},StringSplitOptions.RemoveEmptyEntries);
var pathStruct = root;
List<string> res = new List<string>();
foreach (var s in ss)
{
if (pathStruct != null)
pathStruct = pathStruct.Find(t=>t.name == s);
else
Debug.LogError("resourceUri 错误!");
}
if (pathStruct != null)
{
res = pathStruct.GetChildrenFullPath(true);
}
for (int index = 0; index < res.Count; index++)
{
res[index] = PathTool.Instance.GetSystemHeadPath() + PathTool.Instance.GetStreamAssetsPath() + res[index];
}
return res;
}
}

(其中用到了单例SingleBhv<T>,请参考:http://www.cnblogs.com/fuliufuliu/p/4860685.html)

使用时可以这样:

StreamingAssetAccess.Instance.GetFileList(packageName);

ResourcesPathAccess.Instance.GetFileList(packageName);

填补Resources和WWW加载本地资源的坑

填补Resources和WWW加载本地资源的坑 填补Resources和WWW加载本地资源的坑

遗憾的是在每次编译时和执行时会报红,不过这个错误暂时没发现此红对程序有什么不妥(希望大神指点):

填补Resources和WWW加载本地资源的坑