前言:
一直有个想法,就是把工作中遇到的坑通过自己的深挖总结成一套相同 问题 的解决方案供各位同行拍砖探讨。眼瞅着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/ 文件夹下(的确很任性)

下面我们实现在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;
    }
}

结果如下:

结果是读取成功了。但是你以为到这一步就成功了,那就错了。因为这样的代码到移动端是行不通的,至少2处可以被骂sb:

  • 醉人的地址,地址参数那样写就不用考虑跨平台了。所以这个sb点引出的问题就是在移动端unity3d找不到目标文件。
  • 使用的还是pc上传统的一套读取资源的做法,没有使用unity3d提供的方法,所以可能导致的问题是找得到文件但是没有正确的读取文件内容。

以上用红色标出的问题,便是小匹夫想到的可能出现的问题,也是下文要讨论的内容。那么我们首先来看看资源路径在各个平台上的不同之处吧。

移动平台的资源路径问题
想要读取一个文件,自然首先要找到这个文件,下面小匹夫首先会总结一下unity3d中存在的各个地址,之后再总结一下各个地址在各个移动平台中的对应位置。
Unity3D中的资源路径

Application.dataPath 此属性用于返回程序的数据文件所在文件夹的路径。例如在Editor中就是Assets了。
Application.streamingAssetsPath 此属性用于返回流数据的缓存目录,返回路径为相对路径,适合设置一些外部数据文件的路径。
Application.persistentDataPath 此属性用于返回一个持久化数据存储目录的路径,可以在此路径下存储一些持久化的数据文件。
Application.temporaryCachePath 此属性用于返回一个临时数据的缓存目录。

android平台

Application.dataPath /data/app/xxx.xxx.xxx.apk
Application.streamingAssetsPath jar:file:///data/app/xxx.xxx.xxx.apk/!/assets
Application.persistentDataPath /data/data/xxx.xxx.xxx/files
Application.temporaryCachePath /data/data/xxx.xxx.xxx/cache

IOS平台

Application.dataPath Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxx.app/Data
Application.streamingAssetsPath Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxx.app/Data/Raw
Application.persistentDataPath Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Documents
Application.temporaryCachePath Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Library/Caches

从上面的3张表格,我们可以看到 dataPath和streamingAssetsPath的路径位置一般是相对程序的安装目录位置,而persistentDataPath和temporaryCachePath的路径位置一般是相对所在系统的固定位置。那么现在明确了unity3d中各个地址在不同平台上的含义,下一个问题就来了,也就是我打包之后的资源要怎么和这些地址对应上呢?要知道在pc的editor里默认的资源文件存放的路径就是Assets啊,为何又会派生出那么多路径呢?那么就带着这个疑问,和小匹夫一起进行下文的内容吧。
简单介绍一下unity3d中资源的处理种类(欢迎拍砖):
小匹夫遇到过的大体就是如下几种了,Resources、StreamingAssets、AssetBundle、PersistentDataPath,下面简单分析一下。
Resources: 是作为一个Unity3D的保留文件夹出现的,也就是如果你新建的文件夹的名字叫Resources,那么里面的内容在打包时都会被无条件的打到发布包中。它的特点简单总结一下就是:

  • 只读,即不能动态修改。所以想要动态更新的资源不要放在这里。
  • 会将文件夹内的资源打包集成到.asset文件里面。因此建议可以放一些Prefab,因为Prefab在打包时会自动过滤掉不需要的资源,有利于减小资源包的大小。
  • 主线程加载。
  • 资源读取使用Resources.Load()。

StreamingAssets: 要说到StreamingAssets,其实和Resources还是蛮像的。同样作为一个只读的Unity3D的保留文件夹出现。不过两者也有很大的区别,那就是Resources文件夹中的内容在打包时会被压缩和加密。而StreamingAsset文件夹中的内容则会原封不动的打入包中,因此StreamingAssets主要用来存放一些二进制文件。下面也同样做一个简单的总结:

  • 同样,只读不可写。
  • 主要用来存放二进制文件。
  • 只能用过WWW类来读取。

AssetBundle: 关于AssetBundle的介绍已经有很多了。简而言之就是把prefab或者二进制文件封装成AssetBundle文件(也是一种二进制)。但是也有硬伤,就是在移动端无法更新脚本。下面简单的总结下:

  • 是Unity3D定义的一种二进制类型。
  • 最好将prefab封装成AseetBundle,不过上面不是才说了在移动端无法更新脚本吗?那从Assetbundle中拿到的Prefab上挂的脚本是不是就无法运行了?也不一定,只要这个prefab上挂的是本地脚本,就可以。
  • 使用WWW类来下载。

PersistentDataPath: 看上去它只是个路径呀,可为什么要把它从路径里面单独拿出来介绍呢?因为它的确蛮特殊的,这个路径下是可读写。而且在IOS上就是应用程序的沙盒,但是在可以是程序的沙盒,也可以是sdcard。并且在Android打包的时候,ProjectSetting页面有一个选项Write Access,可以设置它的路径是沙盒还是sdcard。下面同样简单的总结一下:

  • 内容可读写,不过只能运行时才能写入或者读取。提前将数据存入这个路径是不可行的。
  • 无内容限制。你可以从StreamingAsset中读取二进制文件或者从AssetBundle读取文件来写入PersistentDataPath中。
  • 写下的文件,可以在电脑上查看。同样也可以清掉。

好啦,小匹夫介绍到这里,各位看官们是不是也都清楚了一些呢?那么下面我们就开始最后一步了,也就是如何在移动平台如何读取外部文件。

移动平台读取外部文件的方法
上文小匹夫之所以要介绍Resources、StreamingAssets、AssetBundle、PersistentDataPath这四个东东,就是因为读取外部资源的操作所涉及到的东西无外乎这几种。既然是用Unity3D来开发游戏,那么自然要使用Unity3D规定的操作方式,而不是我们在PC上很原始的那种操作方式来操作咯。否则就会像本文一开始所演示的那样,写出移动端无法使用的很傻的代码来。
下面小匹夫就分别实现一下利用Resources、StreamingAssets、AssetBundle来读取的过程。
Resources: 首先我们新建一个Resources目录,并且将上面我们用到的Test.xml复制一份到这个文件夹中。如图:

然后我们通过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);
    }
}

结果如图:

OK,Resources读取外部资源目标达成!!
下面我们继续,这次则是使用StreamingAssets来操作。
StreamingAssets: 同Resources一样,我们要新建一个StreamingAssets的文件夹来存放我们的Test.xml文件。如图:

不过前文已经说了,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);
    }
}

结果如图:

OK,StreamingAssets读取外部资源目标达成!!
下面我们继续,最后则是使用AssetBundle来操作。
AssetBundle: 来到AssetBundle,这里就和上面两个不一样了。首先我们要把我们的文件Test.xml打成AssetBundle文件,由于小匹夫使用的是小米3作为测试机,所以AssetBundle的平台选择为Andorid。
如图,我们创建了一个AssetBundle文件,并命名为TextXML。并且按照二进制文件放入StreamingAssets文件夹中的惯例,将这个AssetBundle文件放入StreamingAssets文件夹。

那么下面就是从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);
    }
     
}

结果如图:

OK,AssetBundle读取外部资源目标也达成了!!

补充: 在此统一回答一下在评论和qq上有同学提出的一个问题:

安卓上Application.persistentDataPath的内容貌似不是匹夫你表里的那个呀?
在本文的评论里小匹夫已经回复过了,其实文中也说过

但是在Android可以是程序的沙盒,也可以是sdcard。并且在Android打包的时候,ProjectSetting页面有一个选项Write Access,可以设置它的路径是沙盒还是sdcard。

下面上图好啦:(求支持,给个回复吧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

匹夫细说Unity3D(一)——移动平台动态读取外部文件全解析相关推荐

  1. 慕容小匹夫 Unity3D移动平台动态读取外部文件全解析

    Unity3D移动平台动态读取外部文件全解析 c#语言规范 阅读目录 前言: 假如我想在editor里动态读取文件 移动平台的资源路径问题 移动平台读取外部文件的方法 补充: 回到目录 前言: 一直有 ...

  2. 乐鑫esp8266学习rtos3.0笔记:esp产品 如何从外部读取 csv 文件的数据,比如从代码读取外部文件阿里云三元组。(附带demo)

    本系列博客学习由非官方人员 半颗心脏 潜心所力所写,不做开发板.仅仅做个人技术交流分享,不做任何商业用途.如有不对之处,请留言,本人及时更改. 1. Esp8266之 搭建开发环境,开始一个" ...

  3. Java电商平台-电商订单系统全解析

    说明:Java电商平台-电商订单系统全解析主要讲解OMS的内容,设计,开发,架构等知识 今天分享将会分为以下三个环节来阐述: 1.订单系统的介绍 2.订单系统的解构 3.垂直电商订单系统设计思路 一. ...

  4. python读取xml文件信息_python读取xml文件方法解析

    关于python读取xml文章很多,但大多文章都是贴一个xml文件,然后再贴个处理文件的代码.这样并不利于初学者的学习,希望这篇文章可以更通俗易懂的教如何使用python来读取xml文件. 什么是xm ...

  5. 转载-慕容小匹夫细说Unity3D(七)——从Draw Call到GC

    可以在这里读到这篇文章:<深入浅出聊优化:从Draw Calls到GC>http://www.cnblogs.com/murongxiaopifu/p/4284988.html 前言: 刚 ...

  6. 【Unity3D日常开发】Unity3D中打包WEBGL后读取本地文件数据

    推荐阅读 CSDN主页 GitHub开源地址 Unity3D插件分享 简书地址 我的个人博客 QQ群:1040082875 大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有 ...

  7. websohere 替换单独文件_postman教程-16-如何读取外部文件实现数据参数化

    测试过程中,常会遇到一个接口要验证很多的测试数据,而要输入参数和验证参数又几乎是一样的.这时我们首先就会想到数据参数化,在postman中也提供了数据参数化功能,它需要把数据单独的存放在一个文件中管理 ...

  8. python读取本地文件-python解析本地HTML文件

    Python使用爬虫技术时,每运行一次,本地都会访问一次主机.为避免完成程序前调试时多次访问主机增加主机负荷,我们可以在编写程序前将网页源代码存在本地,调试时访问本地文件即可.现在我来分享一下爬取资料 ...

  9. python怎么读取pdf文件_Python解析并读取PDF文件内容的方法

    本文实例讲述了Python解析并读取PDF文件内容的方法.分享给大家供大家参考,具体如下: 一.问题描述 利用python,去读取pdf文本内容. 二.效果 三.运行环境 python2.7 四.需要 ...

最新文章

  1. py3提取json指定内容_python3 取页面指定数据(json)
  2. 高校毕业生:今年“太惨了”,网友:更惨的可能还在后头!
  3. 用滑动窗口来解决最长无重复子串问题
  4. 服务器ip被网站屏蔽,各位,服务器IP被别人域名解析如何屏蔽
  5. java二叉树插入节点_[javaSE] 数据结构(二叉查找树-插入节点)
  6. 微信支付的坑(思路)
  7. 单片机C51继电器控制C语言,单片机控制继电器,51单片机控制继电器详细说明
  8. Three.js地图轮廓分割效果
  9. 2、恩智浦-车规级-MCU :S32K11X GPIO实验
  10. Ubuntu下LimeSDR-USB或LimeSDR Mini使用说明
  11. 一个字等于多少字节?
  12. 域名检测监控报警系统
  13. JQuery温故而知新
  14. 拟合程度的评估--判定系数
  15. 电子签约存证及印章管理整体化解决方案
  16. 可获取公网IP的网址
  17. 阿里巴巴矢量图标库icon图标在线引用
  18. FLAC3D 的入门介绍
  19. 如何在MMIT上使用WMLScript文件(How To Use WMLScript Files With MMIT)
  20. 学python推荐的10本豆瓣高分书单,小白到大佬,不看后悔一辈子

热门文章

  1. DockWidget
  2. Docker in Docker dind
  3. Window打开服务的DOS命令
  4. android扩散圆引导动画,Android Material Design(6) CircularReveal圆形扩散动画的使用
  5. Ant Design Pro使用之--EditableProTable 可编辑表格
  6. JVM原理及性能调优
  7. 可以错过班车 不能错过日子
  8. kafka 实践指南
  9. 架构-系统架构设计模块-2
  10. Ubuntu16.04源码编译安装开源版的迅雷Xware Desktop