【轉】unity跨平臺文件操作詳解

今天,這篇文章其實是個老生常談的問題咯,在網上類似的文章也比比皆是,在此我只是做個詳細總結方便大家能夠更好、更快的掌握,當然,如有不足的地方 歡迎指正!!!


相信大家在開發過程中,難免會保存一些文件在客戶端進行本地化操作。
如:配置文件,狀態文件,Assetbundle文件等等...

最近總有人問我:
1.保存了一個xml在客戶端,能讀取裏面的數據,可是不能修改,甚至一修改就報錯...
2.我在電腦上操作文件(xml、text、Assetbundle、json)都沒問題,可是生成打包生成apk、ipa運行就出現各種問題,
要麼數據讀不到,要麼數據不能操作...

這些問題的病症到底出現在什麼地方?又該如何解決?
其實,就是對文件保存的路徑在平臺間的適用性,有些路徑在各個平臺上是不能通用的。
在此我對unity中路徑操作做以下幾種總結:
一.在項目根目錄中創建Resources文件夾來保存文件。
可以使用Resources.Load("文件名字,注:不包括文件後綴名");把文件夾中的對象加載出來
注:此方可實現對文件實施“增刪查改”等操作,但打包後不可以更改了

二.直接放在項目根路徑下來保存文件
在直接使用Application.dataPath來讀取文件進行操作。
注:移動端是沒有訪問權限的。

三.在項目根目錄中創建StreamingAssets文件夾來保存文件
1.可使用Application.dataPath來讀取文件進行操作。
[mw_shl_code=csharp,true]
#if UNITY_EDITOR
string filepath = Application.dataPath +"/StreamingAssets"+"/my.xml";
#elif UNITY_IPHONE
string filepath = Application.dataPath +"/Raw"+"/my.xml";
#elif UNITY_android
string filepath = "jar:file://" + Application.dataPath + "!/assets/"+"/my.xml;
#endif

[/mw_shl_code]
2.直接使用Application.streamingAssetsPath來讀取文件進行操作。
注:此方法在pc/Mac電腦中可實現對文件實施“增刪查改”等操作,但在移動端只支持讀取操作。

四.使用Application.persistentDataPath來操作文件(
該文件存在手機沙盒中,因爲不能直接存放文件,
1.通過服務器直接下載保存到該位置,也可以通過Md5碼比對下載更新新的資源
2.沒有服務器的,只有間接通過文件流的方式從本地讀取並寫入Application.persistentDataPath文件下,然後再通過Application.persistentDataPath來讀取操作。
注:在Pc/Mac電腦 以及Android跟Ipad、ipone都可對文件進行任意操作,另外在IOS上該目錄下的東西可以被iCloud自動備份

五.使用Application.temporaryCachePath來操作文件

操作方式跟上面Application.persistentDataPath類似。除了在IOS上不能被iCloud自動備份。

下圖是幾種文件在Pc中路徑的具體位置
IAWAQ2{}$LA)U@N$EM_98KN.jpg 

其實,在前面我已經發過一篇《Unity中的Path對應各平臺中的Path》的文章,大家可以看看,詳細瞭解下unity在移動平臺中的可操作的具體路徑。
有直接給出各平臺對應路徑喲,方便調試查看。
好了,unity路徑的使用以及注意點都總結了,現在還是送點乾料給大家吧,裏面都有詳細註釋,都是開發中常用的東西
1.對文件的操作類,主要就是文流讀取操作的一些東西(包括Assetbundle)
FileHelper.cs

[mw_shl_code=csharp,true]
using UnityEngine;
using System.Collections;
using System.IO;
using System.Collections.Generic;
using System;
/// <summary>
/// 使用Application.persistentDataPath方式來創建文件,讀寫Xml文件.
/// 注Application.persistentDataPath末尾沒有“/”符號
/// </summary>
public class FileHelper: MonoBehaviour
{
/// <summary>
/// 動態創建文件夾.
/// </summary>
/// <returns>The folder.</returns>
/// <param name="path">文件創建目錄.</param>
/// <param name="FolderName">文件夾名(不帶符號).</param>
public string CreateFolder(string path,string FolderName)
{
string FolderPath = path+FolderName;
if(!Directory.Exists(FolderPath))

Directory.CreateDirectory(FolderPath);

return FolderPath;
}

/// <summary>
/// 創建文件.
/// </summary>
/// <param name="path">完整文件夾路徑.</param>
/// <param name="name">文件的名稱.</param>
/// <param name="info">寫入的內容.</param>
public void CreateFile(string path,string name,string info)
{
//文件流信息
StreamWriter sw;
FileInfo t = new FileInfo(path+name);
if(!t.Exists)
{
//如果此文件不存在則創建
sw = t.CreateText();
}
else
{
//如果此文件存在則打開
sw = t.AppendText();
}
//以行的形式寫入信息
sw.WriteLine(info);
//關閉流
sw.Close();
//銷燬流
sw.Dispose();


/// <summary>
/// 讀取文件.
/// </summary>
/// <returns>The file.</returns>
/// <param name="path">完整文件夾路徑.</param>
/// <param name="name">讀取文件的名稱.</param>
public ArrayList LoadFile(string path,string name)
{
//使用流的形式讀取
StreamReader sr =null;
try{
sr = File.OpenText(path+name);
}catch(Exception e)
{
//路徑與名稱未找到文件則直接返回空
return null;
}
string line;
ArrayList arrlist = new ArrayList();
while ((line = sr.ReadLine()) != null)
{
//一行一行的讀取
//將每一行的內容存入數組鏈表容器中
arrlist.Add(line);
}
//關閉流
sr.Close();
//銷燬流
sr.Dispose();
//將數組鏈表容器返回
return arrlist;

//寫入模型到本地
IEnumerator loadassetbundle(string url)
{
WWW w = new WWW(url);
yield return w;
if (w.isDone)
{
byte[] model = w.bytes;
int length = model.Length;
//寫入模型到本地
CreateassetbundleFile(Application.persistentDataPath, "Model.assetbundle", model,length);
}
}
/// <summary>
/// 獲取文件下所有文件大小
/// </summary>
/// <param name="filePath"></param>
/// <returns></returns>
public int GetAllFileSize(string filePath)
{
int sum = 0;
if (!Directory.Exists(filePath))
{
return 0;
}

DirectoryInfo dti = new DirectoryInfo(filePath);

FileInfo[] fi = dti.GetFiles();

foreach (FileInfo f in fi)
{

sum += Convert.ToInt32(f.Length / 1024);
}

DirectoryInfo[] di = dti.GetDirectories();

if (di.Length > 0)
{
for (int i = 0; i < di.Length; i++)
{
sum += GetAllFileSize(di.FullName);
}
}
return sum;
}
/// <summary>
/// 獲取指定文件大小
/// </summary>
/// <param name="FilePath"></param>
/// <param name="FileName"></param>
/// <returns></returns>
public int GetFileSize(string FilePath, string FileName)
{
int sum = 0;
if (!Directory.Exists(FilePath))
{
return 0;
}
else
{
FileInfo Files = new FileInfo(@FilePath + FileName);
sum += Convert.ToInt32(Files.Length / 1024);
}
return sum;
}
void CreateassetbundleFile(string path, string name, byte[] info, int length)
{
//文件流信息
//StreamWriter sw;
Stream sw;
FileInfo t = new FileInfo(path + "//" + name);
if (!t.Exists)
{
//如果此文件不存在則創建
sw = t.Create();
}
else
{
//如果此文件存在則打開
//sw = t.Append();
return;
}
//以行的形式寫入信息
sw.Write(info, 0, length);
//關閉流
sw.Close();
//銷燬流
sw.Dispose();
}
//讀取本地AssetBundle文件
IEnumerator LoadAssetbundleFromLocal(string path, string name)
{
print("file:///" + path + "/" + name);

WWW w = new WWW("file:///"+path + "/" + name);

yield return w;

if (w.isDone)

{
Instantiate(w.assetBundle.mainAsset);
}
}

/// <summary>
/// 刪除文件.
/// </summary>
/// <param name="path">刪除完整文件夾路徑.</param>
/// <param name="name">刪除文件的名稱.</param>
public void DeleteFile(string path, string name)
{
File.Delete(path + name);
}
/// <summary>
/// 刪除文件
/// </summary>
/// <param name="path"></param>
/// <param name="filesName"></param>
/// <returns></returns>
public bool DeleteFiles(string path, string filesName)
{
bool isDelete = false;
try
{
if (Directory.Exists(path))
{
if (File.Exists(path + "\\" + filesName))
{
File.Delete(path + "\\" + filesName);
isDelete = true;
}
}
}
catch
{
return isDelete;
}
return isDelete;
}
}
[/mw_shl_code]

2.隨機操作類
RandomHelper.cs

[mw_shl_code=csharp,true]
using UnityEngine;
using System.Collections;
/// <summary>
/// 隨機操作類
/// </summary>
public class RandomHelper 
{
private static char[] constant = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' };
/// <summary>
/// 字符串隨機
/// </summary>
/// <param name="Length">要隨機的位數</param>
/// <returns></returns>
public string GenerateRandomNumber(int Length)
{
System.Text.StringBuilder newRandom = new System.Text.StringBuilder(62);
for (int i = 0; i < Length; i++)
{
newRandom.Append(constant[Random.Range(0,62)]);
}
return newRandom.ToString();
}
private static char[] constant1 = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
/// <summary>
/// 數字隨機
/// </summary>
/// <param name="Length">要隨機的位數</param>
/// <returns></returns>
public string GenerateNumber(int Length)
{
System.Text.StringBuilder newRandom = new System.Text.StringBuilder(10);
for (int i = 0; i < Length; i++)
{
newRandom.Append(constant1[Random.Range(0, 10)]);
}
return newRandom.ToString();
}
/// <summary>
/// 字符串數組隨機
/// </summary>
/// <param name="chars">數組</param>
/// <param name="Length">隨機的位數</param>
/// <returns></returns>
public string GetStrRandomSurname(string[] chars, int Length)
{
int count = chars.Length;
System.Text.StringBuilder newRandom = new System.Text.StringBuilder(count);

for (int i = 0; i < Length; i++)
{
newRandom.Append(chars[Random.Range(0, count)]);
}
return newRandom.ToString();
}
/// <summary>
/// 字符串*截取
/// </summary>
/// <param name="str">字符串</param>
/// <returns></returns>
public string[] getStringToList(string str)
{
return str.Split('*');
}
}[/mw_shl_code]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章