关于Unity的特殊文件夹——StreamingAssets

介绍

​ StreamingAssets文件是Unity的特殊文件之一。在Unity进行打包操作的时候,StreamingAsset文件不会像Resource文件一样被Unity进行压缩。所以一般而言,StreamingAssets用来存储一些你不想被Unity压缩的文件,比如游戏场景中的敌人的配置信息、UI的配置信息。StreamingAssets文件和Resources文件一样,他们都只能读而不能写。实际上,StreamingAssets文件在一些平台上仍然可以修改。可它的确在一些平台中不可修改。故为了平台之间的兼容性,StreamingAssets下的文件最好不要修改。

关于StreamingAssets的位置

​ 在不同的平台中,游戏文件的存放位置也是不同的。而StreamingAssets文件不像Resources文件一样可以使用Unity提供的Resources API进行直接的读取操作。我们要首先知道StreamingAssets在不同平台下的位置。这个位置可能会随时间的变化而改变,所以你可以点击此链接https://docs.unity.cn/cn/current/Manual/StreamingAssets.html查看官方文档中说明的不同平台下StreamingAssets文件的位置。

1
2
3
4
5
6
7
#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
prPath = Application.dataPath + "/StreamingAssets/";
#elif UNITY_IOS
prPath = "file://" + Application.dataPath + "/Raw/";
#elif UNITY_ANDROID
prPath = "file://" + Application.dataPath + "!/Assets/";
#endif

​ 上面的代码可以得到不同平台下StreamingAssets文件的位置。(此时我的Unity版本2020.3.0f1c1)

关于StreamingAssets的读取

​ 前面我也说过StreamingAssets文件不能像Resources文件一样有Unity官方专门提供的API进行读取。但是我们仍然可以使用Unity官方提供的其他API对StreamingAssets文件下的内容进行读取。如果你有看过上面的链接,你会发现Unity官方也说明了读取StreamingAssets文件的API——UnityWebRequest(其在UnityEngine.Networking空间下)。在一些其他的版本中,你也会发现有人使用API:www进行StreamingAssets文件的读取。但是www现在已经被Unity官方弃用了。可他们的使用方法还是差不多。

​ UnityWebRequest中的方法大都是异步调用的。(UnityWebRequest的官方说明链接:https://docs.unity.cn/cn/current/ScriptReference/Networking.UnityWebRequest.html)所以其对于文件的读取是要有一定时间的。一般而言,我们用使用一个协程去等待其执行完毕然后再进行后面的步骤。但是你也可以在其他地方中看到以下的代码:

1
2
3
4
5
6
7
8
9
10
11
12
public string GetFromStreamingAssets(string url)
{
UnityWebRequest request = UnityWebRequest.Get(url);
request.SendWebRequest();
while(true)
{
if(request.downloadHandler.isDone)
{
return request.downloadHandler.text;
}
}
}

​ 上面的代码使用了while循环代替了官方例子(链接)中yield return request.SendWebRequest();。虽然这个方法确实能够做到访问StreamingAssets文件目录下的内容,但是其默认所给的路径都是正确路径而不像官方例子中存在结果检测。当我们给其一个错误的路径时request.downloadHandler.isDone将会一直为false,因此我们会一直在循环中进而造成游戏的卡死。

1
2
3
4
5
6
7
8
9
10
11
12
13
switch (webRequest.result)
{
case UnityWebRequest.Result.ConnectionError:
case UnityWebRequest.Result.DataProcessingError:
Debug.LogError(pages[page] + ": Error: " + webRequest.error);
break;
case UnityWebRequest.Result.ProtocolError:
Debug.LogError(pages[page] + ": HTTP Error: " + webRequest.error);
break;
case UnityWebRequest.Result.Success:
Debug.Log(pages[page] + ":\nReceived: " + webRequest.downloadHandler.text);
break;
}

​ 上面的代码是Unity官方例子中对于UnityWebRequest请求结果的处理。具体的UnityWebRequest请求结果可以查看官方文档中的介绍:https://docs.unity.cn/cn/current/ScriptReference/Networking.UnityWebRequest.Result.html。下面是我从Unity官方文档中复制下来的信息(不知道为什么我只能看到英文的说法,所以我自己翻译了一下。如果有错请多包涵)

InProgress 请求还未完成
Success 请求成功
ConnectionError 与服务器通信失败。例如,请求无法连接或无法建立安全通道。
ProtocolError 服务器返回一个错误的回应。请求与服务器成功建立了连接,但是接收到如链接协议定义的错误。
DataProcessingError 错误处理数据。请求与服务器通信成功,但在处理接收到的数据时遇到错误。例如,数据已损坏或格式不正确。

​ 这些结果中有一个结果是显示请求还未完成。所以我们可以把上面会死循环的代码改为下面的形式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public string GetFromStreamingAssets(string url)
{
UnityWebRequest request = UnityWebRequest.Get(url);
request.SendWebRequest();
while(request.result == UnityWebRequest.Result.InProgress)
{
//因为SendWebRequest是异步进行的,所以可能在循环中就完成了。当然不用也可以。
if(request.downloadHandler.isDone)
{
return request.downloadHandler.text;
}
}
if(request.downloadHandler.isDone)
{
return request.downloadHandler.text;
}
Debug.log("请求失败");
return null;
}

​ 如果请求失败了,那么请求也算结束了,程序会退出while的循环。而请求如果成功了,则request.downloadHandler.isDone为真也会退出while循环。