UNITY_資源路徑與加載外部文件

UNITY_資源路徑與加載外部文件

https://www.tuicool.com/articles/qMNnmm6
https://blog.csdn.net/appppppen/article/details/51396256
https://unity3d.com/cn/learn/tutorials/topics/best-practices/resources-folder
https://blog.csdn.net/qq_18995513/article/details/51958906bootstrap

背景:

有許多靜態數據是放在客戶端中的,好比csv/xml文件,是須要動態讀取文件的api

實例: 動態讀取一個xml文件,並生成一個類緩存

<?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>

將此xml文件隨意放在某路徑下:Assets/aa/bb/Test.xml網絡

使用代碼讀取文件內容app

void Start() {
    XElement result = LoadXML("Assets/aa/bb/Test.xml");
}

void LoadXML(string path) {
    XElement xml = XElement.Load(path);
    return xml;
}

讀取成功。異步

問題1. 路徑和地址。在移動端是找不到文件的。
問題2. 使用的是PC上傳統的一套讀取資源的作法,而沒有使用unity3d提供的方法。
  可能致使找獲得文件可是沒能正確地讀取文件內容函數

移動平臺的資源路徑:

Application.dataPath: 程序的數據文件所在文件夾。在Editor中就是Assets
  安卓: /data/app/xxx.xxx.xxx.apk
  iOS:  Application/xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxx.app/Dataui

Application.streamingAssetsPath: 流數據的緩存目錄,爲相對路徑,適合設置一些外部數據文件
  安卓: jar:file:///data/app/xxx.xxx.xxx.apk/!/assets
  iOS:  Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/xxx.app/Data/Raw加密

Application.persistentDataPath: 持久化數據存儲目錄的路徑,可用於存儲一些持久化的數據文件
  安卓: /data/data/xxx.xxx.xxx/files
  iOS:  Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Documentsspa

Application.temporaryCachePath: 臨時數據的緩存目錄
  安卓: /data/data/xxx.xxx.xxx/cache
  iOS:  Application/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/Library/Caches

dataPath和streamingAssetsPath通常是相對程序的安裝目錄位置
persistentDataPath和temporaryCachePath通常是與系統有關的固定位置

那麼,打包以後的資源的路徑如何與這些地址對應上呢?

Unity中的資源處理種類:

Resources:

若是有文件夾名爲Resources,則裏面的內容會無條件地在打包時打包集成到.asset文件中
能夠放置一些Prefab,由於Prefab在打包時會自動過濾掉不須要的資源,有利於減少資源包
1. 只讀。不能動態修改,會動態更新的資源不要放在這裏
2. 主線程加載
3. 使用Resources.Load()加載資源

StreamingAssets:

與Resources相似
區別爲:Resources文件夾中的內容在打包時會被壓縮和加密,而StreamingAssets中的內容則原封不動地打包
通常用來存放一些二進制文件
1. 只讀,不能動態修改
2. 主要存放二進制文件
3. 只能經過WWW類讀取

AssetBundle:

將prefab或二進制文件封裝成AssetBundle文件(也是二進制文件)
缺點: 在移動端沒法更新腳本
總結:
1. 該二進制文件(AssetBundle文件) 是Unity3D定義的一種二進制類型
2. 最好將Prefab封裝成AssetBundle,可是在移動端沒法更新腳本
3. 使用WWW類讀取

PersistentDataPath:

這是一個路徑(可讀寫)
在iOS上就是應用程序的沙盒;
在安卓上能夠是程序的沙盒或sdCard -- 在安卓打包時,ProjectSetting的選項WriteAccess可設置路徑是沙盒仍是sdcard
總結:
1. 內容在運行時可讀寫,提早將數據存入這個路徑是不可行的
2. 無內容類型的限制
3. 寫下的文件能夠在電腦上查看,一樣也能夠在電腦中清除

移動平臺讀取外部文件的方法:

使用Unity3D規定的操做方式來讀取外部資源:Resources/ StreamingAssets/ AssetBundle

Resources: 

新建Resources目錄,在目錄中建立文件Test.xml(以前在背景中提到的那個文件)
經過Resources的方法來讀取Test.xml中的內容。

public class Test: MonoBehaviour {
    private string _result;
    void Start(){  LoadXML("Test");  }

    private void LoadXML(string path){
        _result = Resources.Load(path).ToString();
        XmlDocument doc = new XmlDocument();
        doc.LoadXml(_result);
    }
}

StreamingAssets:

新建StreamingAssets文件夾並存放Test.xml文件
(StreamingAssets文件夾中的文件不會被壓縮或加密,因此通常是要放二進制文件的,這裏放xml只是作一個演示,實際操做中切記不要直接把數據文件放到該目錄中)

public class Test : MonoBehaviour {
    private string _result;
    void Start(){  StartCoroutine(LoadXML());  }

    IEnumerator LoadXML(){
        string path = Application.streamingAssetsPath;
        WWW www = new WWW(path);
        yield return www;
        _result = www.text;
    }
}

AssetBundle:

比較麻煩,須要先把Test.xml打包成AssetBundle文件
建立好AssetBundle文件並命名爲TestXML後,由於ab文件是二進制文件,所以放入StreamingAssets文件夾。

public class Test: MonoBehaviour {
    private string _result;
    void Start(){  LoadXML();  }

    void LoadXML(){
        AssetBundle assetBundleCsv = new AssetBundle();
        // 讀取放入StreamingAssets文件夾中的ab文件
        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();
    }
}

PersistentDataPath:

只有在運行時才能讀寫,例如經過網絡下載資源存放在PersistantDataPath中

與StreamingAssets的讀取很相似,但要注意經過www類加載PersistentDataPath必須使用file://協議實現加載

public class Test: MonoBehaviour{
    private string _result;
    void Start(){  StartCoroutine(LoadXML());  }

    private void LoadXML(){
        string path = "file://" + Application.persistentDataPath + "/test.xml";
        WWW www = new WWW(path);
        yield return www;
        _result = www.text;
    }
}

深刻Resources.Load()

Recommendation: DO NOT USE IT.

Reasons:

1. Use of the Resources folder makes fine-grained memory management more difficult;

2. Improper use of Resources folders will increase applicaiton startup time and the length of builds
  The increase of the number of Resources folders makes the management of the "Resources Assets" more difficult;

3. The Resources system degrades a project's ability to deliver custom content to specific platforms and eliminates the possibility of incremental content upgrades
  AssetBundle Variants are Unity's primary tool for adjusting content on a per-device basis

Proper uses:

Two specific use cases where Resources system can be helpful

1. The ease of the Resources folder makes it an excellent system to rapidly prototype.
  But when a project moves into full production, the use of Resources system should be eliminated.

2. When the content is:
  Generally required throughout a project's lifetime
  Not memory-intensive
  Not prone to patching, or does not vary across platforms/ devices
  Used for minimal bootstrapping

  好比: 持有預製體的MonoBehaviour單例、包含第三方配置數據的ScriptableObject容器等

Resources的卸載:

Resources資源類型的加載方式只有一種,但卸載有多種。

1. Resources.UnloadAsset(Object assetToUnload)
  從內存中卸載(非GameObject類型的資源???),會將內存中已加載的資源卸載掉
2. Destroy(obj) 
  僅用於卸載(GameObject類型???)的資源的克隆體
3. DestroyImmediately(obj)
  卸載GameObject類型的資源,會將內存中已加載資源及其克隆體卸載;
  但該方法只能用在非編輯模式下,不然會報錯,提示改成DestroyImmediately(obj, true),
  然而編輯模式下使用該函數會連文件夾裏的原始Asset一併刪除。

官方推薦的卸載方法爲:
  public static AsyncOperation UnloadUnusedAssets()  異步檢索資源若是沒有被使用纔會卸載。  被全局變量引用的資源會致使一直沒法釋放。

相關文章
相關標籤/搜索