前言:
一直有个想法,就是把工作中遇到的坑通过自己的深挖总结成一套相同 问题 的解决方案供各位同行拍砖探讨。眼瞅着2015年第一个工作日就要来到了,小匹夫也休息的差不多了,寻思着也该写点东西活动活动大脑和手指了。那么今天开始,小匹夫会记录一些平时工作中遇到的坑,以及小匹夫的应对方法,欢迎各位拍砖讨论。那么今天主要讨论一下3D在移动端如何动态的读取外部文件,比如csv(txt),xml一类的文件。主要涉及的问题,就是PC端上本来测试的好好的东西,到了移动端就不能用了,所以要讨论一下PC端和移动端的区别,那么下一个问题自然而然的就是移动端的资源路径(要讨论一下Resources、StreamingAssets、AssetBundle、PersistentDataPath),最后一步就是找到了资源如何读取(这里也会具体到对应的几种情况,即Resources、StreamingAssets、AssetBundle),主要的思路就是这样啦。对嘞,前言部分还是要祝各位看官新的一年身体健康,升职加薪。
假如我想在editor里动态读取文件
实际的游戏开发中,其实有相当一部分静态数据是可以放在客户端的,所以势必会产生要动态读取这些文件的需求,比如csv(其实就是文本文件),xml等等。我相信大家不管是用win还是用mac来做 unity 3d的开发,都一定要先在editor中去实现基本的功能,在具体到各个移动平台上去调试。所以作为要读取外部文件的第一步,显然我们要先在editor也就是pc上实现这个功能。
下面给各位举一个读取xml的例子,也是我在以前的一篇文章《自己动手之使用反射和泛型,动态读取XML创建类实例并赋值》中使用过的,动态读取一个xml文件并动态生成一个类。
下面是我们用来做例子的xml文件,Test.xml:
我们就可以很任性的把这个文件随便丢在一个地方,只要你能指定对它的地址。例如我还把它放在那篇文章中的地址 Assets/xml-to-egg/xml-to-egg-test/ 文件夹下(的确很任性)
下面我们实现在PC上读取这个文件内容的代码:
结果如下:
结果是读取成功了。但是你以为到这一步就成功了,那就错了。因为这样的代码到移动端是行不通的,至少2处可以被骂sb:
移动平台的资源路径问题
想要读取一个文件,自然首先要找到这个文件,下面小匹夫首先会总结一下unity3d中存在的各个地址,之后再总结一下各个地址在各个移动平台中的对应位置。
Unity3D中的资源路径
android平台
IOS平台
从上面的3张表格,我们可以看到 dataPath和streamingAssetsPath的路径位置一般是相对程序的安装目录位置,而persistentDataPath和temporaryCachePath的路径位置一般是相对所在系统的固定位置。那么现在明确了unity3d中各个地址在不同平台上的含义,下一个问题就来了,也就是我打包之后的资源要怎么和这些地址对应上呢?要知道在pc的editor里默认的资源文件存放的路径就是Assets啊,为何又会派生出那么多路径呢?那么就带着这个疑问,和小匹夫一起进行下文的内容吧。
简单介绍一下unity3d中资源的处理种类(欢迎拍砖):
小匹夫遇到过的大体就是如下几种了,Resources、StreamingAssets、AssetBundle、PersistentDataPath,下面简单分析一下。
Resources: 是作为一个Unity3D的保留文件夹出现的,也就是如果你新建的文件夹的名字叫Resources,那么里面的内容在打包时都会被无条件的打到发布包中。它的特点简单总结一下就是:
移动平台读取外部文件的方法
上文小匹夫之所以要介绍Resources、StreamingAssets、AssetBundle、PersistentDataPath这四个东东,就是因为读取外部资源的操作所涉及到的东西无外乎这几种。既然是用Unity3D来开发游戏,那么自然要使用Unity3D规定的操作方式,而不是我们在PC上很原始的那种操作方式来操作咯。否则就会像本文一开始所演示的那样,写出移动端无法使用的很傻的代码来。
下面小匹夫就分别实现一下利用Resources、StreamingAssets、AssetBundle来读取的过程。
Resources: 首先我们新建一个Resources目录,并且将上面我们用到的Test.xml复制一份到这个文件夹中。如图:
然后我们通过Resources的读取方法来读取Test.xml的内容。并且调用GUI将xml的内容绘制出来。
结果如图:
OK,Resources读取外部资源目标达成!!
下面我们继续,这次则是使用StreamingAssets来操作。
StreamingAssets: 同Resources一样,我们要新建一个StreamingAssets的文件夹来存放我们的Test.xml文件。如图:
不过前文已经说了,StreamingAssets文件夹内的东西并不会被压缩和加密,而是放进去什么就是什么,所以一般是要放二进制文件的,这里小匹夫仅仅做一个演示,各位在实际操作中切记不要直接把数据文件放到这个目录中打包。
结果如图:
OK,StreamingAssets读取外部资源目标达成!!
下面我们继续,最后则是使用AssetBundle来操作。
AssetBundle: 来到AssetBundle,这里就和上面两个不一样了。首先我们要把我们的文件Test.xml打成AssetBundle文件,由于小匹夫使用的是小米3作为测试机,所以AssetBundle的平台选择为Andorid。
如图,我们创建了一个AssetBundle文件,并命名为TextXML。并且按照二进制文件放入StreamingAssets文件夹中的惯例,将这个AssetBundle文件放入StreamingAssets文件夹。
那么下面就是从AssetBudle中读取Test.xml的内容咯。直接上代码:
结果如图:
OK,AssetBundle读取外部资源目标也达成了!!
补充: 在此统一回答一下在评论和qq上有同学提出的一个问题:
安卓上Application.persistentDataPath的内容貌似不是匹夫你表里的那个呀?
在本文的评论里小匹夫已经回复过了,其实文中也说过
这样,我们就实现了几种动态读取外部文件的操作。各位看官是否看明白了呢?当然文章仓促,还有很多不足,欢迎大家拍砖探讨~
装模作样的声明一下:本博文章若非特殊注明皆为原创,若需转载请保留原文链接(http://www.cnblogs.com/murongxiaopifu/p/4199541.html)及作者信息慕容小匹夫 (http://www.cnblogs.com/murongxiaopifu)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
匹夫细说Unity3D(一)——移动平台动态读取外部文件全解析
http://www.unitymanual.com/thread-35771-1-1.html
匹夫细说Unity3D(二)——用反射、泛型读取XML后动态创建实例并赋值
http://www.unitymanual.com/thread-36006-1-1.html
匹夫细说Unity3D(三)——为何能跨平台?聊聊CIL(MSIL)
http://www.unitymanual.com/thread-36240-1-1.html
匹夫细说Unity3D(四)——常用数据结构大起底
http://www.unitymanual.com/thread-36420-1-1.html
一直有个想法,就是把工作中遇到的坑通过自己的深挖总结成一套相同 问题 的解决方案供各位同行拍砖探讨。眼瞅着2015年第一个工作日就要来到了,小匹夫也休息的差不多了,寻思着也该写点东西活动活动大脑和手指了。那么今天开始,小匹夫会记录一些平时工作中遇到的坑,以及小匹夫的应对方法,欢迎各位拍砖讨论。那么今天主要讨论一下3D在移动端如何动态的读取外部文件,比如csv(txt),xml一类的文件。主要涉及的问题,就是PC端上本来测试的好好的东西,到了移动端就不能用了,所以要讨论一下PC端和移动端的区别,那么下一个问题自然而然的就是移动端的资源路径(要讨论一下Resources、StreamingAssets、AssetBundle、PersistentDataPath),最后一步就是找到了资源如何读取(这里也会具体到对应的几种情况,即Resources、StreamingAssets、AssetBundle),主要的思路就是这样啦。对嘞,前言部分还是要祝各位看官新的一年身体健康,升职加薪。
假如我想在editor里动态读取文件
实际的游戏开发中,其实有相当一部分静态数据是可以放在客户端的,所以势必会产生要动态读取这些文件的需求,比如csv(其实就是文本文件),xml等等。我相信大家不管是用win还是用mac来做 unity 3d的开发,都一定要先在editor中去实现基本的功能,在具体到各个移动平台上去调试。所以作为要读取外部文件的第一步,显然我们要先在editor也就是pc上实现这个功能。
下面给各位举一个读取xml的例子,也是我在以前的一篇文章《自己动手之使用反射和泛型,动态读取XML创建类实例并赋值》中使用过的,动态读取一个xml文件并动态生成一个类。
下面是我们用来做例子的xml文件,Test.xml:
[XML]
纯文本查看
复制代码
1
2
3
4
5
6
|
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<
test
>
<
name
>chenjd</
name
>
<
blog
>http://www.cnblogs.com/murongxiaopifu/</
blog
>
<
organization
>Fanyoy</
organization
>
<
age
>25</
age
>
</
test
>
|
我们就可以很任性的把这个文件随便丢在一个地方,只要你能指定对它的地址。例如我还把它放在那篇文章中的地址 Assets/xml-to-egg/xml-to-egg-test/ 文件夹下(的确很任性)
![](http://images.cnitblog.com/blog/686199/201501/031536184503480.png)
下面我们实现在PC上读取这个文件内容的代码:
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
//读取xml测试
using
UnityEngine;
using
System.Collections;
using
EggToolkit;
using
System.Xml.Linq;
public
class
Test : MonoBehaviour {
// Use this for initialization
void
Start () {
XElement result = LoadXML(
"Assets/xml-to-egg/xml-to-egg-test/Test.xml"
);
//任性的地址
Debug.Log(result.ToString());
}
// Update is called once per frame
void
Update () {
}
private
XElement LoadXML(
string
path)
{
XElement xml = XElement.Load(path);
return
xml;
}
}
|
结果如下:
![](http://images.cnitblog.com/blog/686199/201501/031541520918018.png)
结果是读取成功了。但是你以为到这一步就成功了,那就错了。因为这样的代码到移动端是行不通的,至少2处可以被骂sb:
- 醉人的地址,地址参数那样写就不用考虑跨平台了。所以这个sb点引出的问题就是在移动端unity3d找不到目标文件。
- 使用的还是pc上传统的一套读取资源的做法,没有使用unity3d提供的方法,所以可能导致的问题是找得到文件但是没有正确的读取文件内容。
移动平台的资源路径问题
想要读取一个文件,自然首先要找到这个文件,下面小匹夫首先会总结一下unity3d中存在的各个地址,之后再总结一下各个地址在各个移动平台中的对应位置。
Unity3D中的资源路径
简单介绍一下unity3d中资源的处理种类(欢迎拍砖):
小匹夫遇到过的大体就是如下几种了,Resources、StreamingAssets、AssetBundle、PersistentDataPath,下面简单分析一下。
Resources: 是作为一个Unity3D的保留文件夹出现的,也就是如果你新建的文件夹的名字叫Resources,那么里面的内容在打包时都会被无条件的打到发布包中。它的特点简单总结一下就是:
- 只读,即不能动态修改。所以想要动态更新的资源不要放在这里。
- 会将文件夹内的资源打包集成到.asset文件里面。因此建议可以放一些Prefab,因为Prefab在打包时会自动过滤掉不需要的资源,有利于减小资源包的大小。
- 主线程加载。
- 资源读取使用Resources.Load()。
- 同样,只读不可写。
- 主要用来存放二进制文件。
- 只能用过WWW类来读取。
- 是Unity3D定义的一种二进制类型。
- 最好将prefab封装成AseetBundle,不过上面不是才说了在移动端无法更新脚本吗?那从Assetbundle中拿到的Prefab上挂的脚本是不是就无法运行了?也不一定,只要这个prefab上挂的是本地脚本,就可以。
- 使用WWW类来下载。
- 内容可读写,不过只能运行时才能写入或者读取。提前将数据存入这个路径是不可行的。
- 无内容限制。你可以从StreamingAsset中读取二进制文件或者从AssetBundle读取文件来写入PersistentDataPath中。
- 写下的文件,可以在电脑上查看。同样也可以清掉。
移动平台读取外部文件的方法
上文小匹夫之所以要介绍Resources、StreamingAssets、AssetBundle、PersistentDataPath这四个东东,就是因为读取外部资源的操作所涉及到的东西无外乎这几种。既然是用Unity3D来开发游戏,那么自然要使用Unity3D规定的操作方式,而不是我们在PC上很原始的那种操作方式来操作咯。否则就会像本文一开始所演示的那样,写出移动端无法使用的很傻的代码来。
下面小匹夫就分别实现一下利用Resources、StreamingAssets、AssetBundle来读取的过程。
Resources: 首先我们新建一个Resources目录,并且将上面我们用到的Test.xml复制一份到这个文件夹中。如图:
![](http://images.cnitblog.com/blog/686199/201501/031824262944120.png)
然后我们通过Resources的读取方法来读取Test.xml的内容。并且调用GUI将xml的内容绘制出来。
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
|
//用Resources读取xml
using
UnityEngine;
using
System.Collections;
using
EggToolkit;
using
System.Xml.Linq;
using
System.Xml;
public
class
Test : MonoBehaviour {
private
string
_result;
// Use this for initialization
void
Start () {
LoadXML(
"Test"
);
}
// Update is called once per frame
void
Update () {
}
private
void
LoadXML(
string
path)
{
_result = Resources.Load(path).ToString();
XmlDocument doc =
new
XmlDocument();
doc.LoadXml(_result);
}
void
OnGUI()
{
GUIStyle titleStyle =
new
GUIStyle();
titleStyle.fontSize = 20;
titleStyle.normal.textColor =
new
Color(46f/256f, 163f/256f, 256f/256f, 256f/256f);
GUI.Label(
new
Rect(400, 10, 500, 200), _result,titleStyle);
}
}
|
结果如图:
![](http://images.cnitblog.com/blog/686199/201501/031828380286047.png)
OK,Resources读取外部资源目标达成!!
下面我们继续,这次则是使用StreamingAssets来操作。
StreamingAssets: 同Resources一样,我们要新建一个StreamingAssets的文件夹来存放我们的Test.xml文件。如图:
![](http://images.cnitblog.com/blog/686199/201501/032015457313880.png)
不过前文已经说了,StreamingAssets文件夹内的东西并不会被压缩和加密,而是放进去什么就是什么,所以一般是要放二进制文件的,这里小匹夫仅仅做一个演示,各位在实际操作中切记不要直接把数据文件放到这个目录中打包。
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
using
UnityEngine;
using
System.Collections;
using
EggToolkit;
using
System.Xml.Linq;
using
System.Xml;
using
System.IO;
public
class
Test : MonoBehaviour {
private
string
_result;
// Use this for initialization
void
Start () {
StartCoroutine(LoadXML());
}
// Update is called once per frame
void
Update () {
}
/// <summary>
/// 如前文所述,streamingAssets只能使用www来读取,
/// 如果不是使用www来读取的同学,就不要问为啥读不到streamingAssets下的内容了。
/// 这里还可以使用了persistenDataPath来保存从streamingassets那里读到内容。
/// </summary>
IEnumerator LoadXML()
{
string
sPath= Application.streamingAssetsPath +
"/Test.xml"
;
WWW www =
new
WWW(sPath);
yield
return
www;
_result = www.text;
}
void
OnGUI()
{
GUIStyle titleStyle =
new
GUIStyle();
titleStyle.fontSize = 20;
titleStyle.normal.textColor =
new
Color(46f/256f, 163f/256f, 256f/256f, 256f/256f);
GUI.Label(
new
Rect(400, 10, 500, 200), _result,titleStyle);
}
}
|
结果如图:
![](http://images.cnitblog.com/blog/686199/201501/032008488563405.png)
OK,StreamingAssets读取外部资源目标达成!!
下面我们继续,最后则是使用AssetBundle来操作。
AssetBundle: 来到AssetBundle,这里就和上面两个不一样了。首先我们要把我们的文件Test.xml打成AssetBundle文件,由于小匹夫使用的是小米3作为测试机,所以AssetBundle的平台选择为Andorid。
如图,我们创建了一个AssetBundle文件,并命名为TextXML。并且按照二进制文件放入StreamingAssets文件夹中的惯例,将这个AssetBundle文件放入StreamingAssets文件夹。
![](http://images.cnitblog.com/blog/686199/201501/032029359195921.png)
那么下面就是从AssetBudle中读取Test.xml的内容咯。直接上代码:
[C#]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
//从AssetBundle中读取xml
using
EggToolkit;
using
System.Xml.Linq;
using
System.Xml;
using
System.IO;
public
class
Test : MonoBehaviour {
private
string
_result;
// Use this for initialization
void
Start () {
LoadXML();
}
// Update is called once per frame
void
Update () {
}
void
LoadXML()
{
AssetBundle AssetBundleCsv =
new
AssetBundle();
//读取放入StreamingAssets文件夹中的bundle文件
string
str = Application.streamingAssetsPath +
"/"
+
"TestXML.bundle"
;
WWW www =
new
WWW(str);
www = WWW.LoadFromCacheOrDownload(str, 0);
AssetBundleCsv = www.assetBundle;
string
path =
"Test"
;
TextAsset test = AssetBundleCsv.Load(path,
typeof
(TextAsset))
as
TextAsset;
_result = test.ToString();
}
void
OnGUI()
{
GUIStyle titleStyle =
new
GUIStyle();
titleStyle.fontSize = 20;
titleStyle.normal.textColor =
new
Color(46f/256f, 163f/256f, 256f/256f, 256f/256f);
GUI.Label(
new
Rect(400, 10, 500, 200), _result,titleStyle);
}
}
|
结果如图:
![](http://images.cnitblog.com/blog/686199/201501/032251342477557.png)
OK,AssetBundle读取外部资源目标也达成了!!
补充: 在此统一回答一下在评论和qq上有同学提出的一个问题:
安卓上Application.persistentDataPath的内容貌似不是匹夫你表里的那个呀?
在本文的评论里小匹夫已经回复过了,其实文中也说过
下面上图好啦:(求支持,给个回复吧T.T)
这样,我们就实现了几种动态读取外部文件的操作。各位看官是否看明白了呢?当然文章仓促,还有很多不足,欢迎大家拍砖探讨~
装模作样的声明一下:本博文章若非特殊注明皆为原创,若需转载请保留原文链接(http://www.cnblogs.com/murongxiaopifu/p/4199541.html)及作者信息慕容小匹夫 (http://www.cnblogs.com/murongxiaopifu)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
匹夫细说Unity3D(一)——移动平台动态读取外部文件全解析
http://www.unitymanual.com/thread-35771-1-1.html
匹夫细说Unity3D(二)——用反射、泛型读取XML后动态创建实例并赋值
http://www.unitymanual.com/thread-36006-1-1.html
匹夫细说Unity3D(三)——为何能跨平台?聊聊CIL(MSIL)
http://www.unitymanual.com/thread-36240-1-1.html
匹夫细说Unity3D(四)——常用数据结构大起底
http://www.unitymanual.com/thread-36420-1-1.html