新的答案(Unity 2017.2及以上版本):
使用UnityWebRequest
和DownloadHandlerFile
,DownloadHandlerFile
类是新的,用于直接下载和保存文件,同时避免高内存使用。
IEnumerator Start()
{
string url = "http://dl3.webmfiles.org/big-buck-bunny_trailer.webm";
string vidSavePath = Path.Combine(Application.persistentDataPath, "Videos");
vidSavePath = Path.Combine(vidSavePath, "MyVideo.webm");
if (!Directory.Exists(Path.GetDirectoryName(vidSavePath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(vidSavePath));
}
var uwr = new UnityWebRequest(url);
uwr.method = UnityWebRequest.kHttpVerbGET;
var dh = new DownloadHandlerFile(vidSavePath);
dh.removeFileOnAbort = true;
uwr.downloadHandler = dh;
yield return uwr.SendWebRequest();
if (uwr.isNetworkError || uwr.isHttpError)
Debug.Log(uwr.error);
else
Debug.Log("Download saved to: " + vidSavePath.Replace("/", "\\") + "\r\n" + uwr.error);
}
旧版答案 (Unity 2017.1及以下版本)(如果要在文件下载时访问每个字节,请使用此选项)
这种问题是 Unity 的 UnityWebRequest
产生的原因,但它不能直接使用,因为最新版本的 Unity 中的 WWW
API 是在 UnityWebRequest
API 之上实现的,这意味着如果您使用 WWW
API 发生错误,则也可能会出现同样的错误 UnityWebRequest
。即使它可以工作,您也可能在像 Android 这样内存较小的移动设备上遇到问题。
解决方法是使用 UnityWebRequest 的 DownloadHandlerScript
功能,该功能允许您以块状形式下载数据。通过以块状形式下载数据,您可以防止引起溢出错误。 WWW
API 没有实现此功能,因此必须使用 UnityWebRequest
和 DownloadHandlerScript
来以块状形式下载数据。您可以在此处了解其工作原理。
虽然这应该解决您当前的问题,但在尝试使用 File.WriteAllBytes
保存大量数据时,您可能会遇到另一个内存问题。使用 FileStream
来执行保存部分,并仅在下载完成后关闭它。
创建一个自定义的 UnityWebRequest
以按块下载数据:
using System;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
public class CustomWebRequest : DownloadHandlerScript
{
public CustomWebRequest()
: base()
{
}
public CustomWebRequest(byte[] buffer)
: base(buffer)
{
Init();
}
protected override byte[] GetData() { return null; }
protected override bool ReceiveData(byte[] byteFromServer, int dataLength)
{
if (byteFromServer == null || byteFromServer.Length < 1)
{
Debug.Log("CustomWebRequest :: ReceiveData - received a null/empty buffer");
return false;
}
AppendFile(byteFromServer, dataLength);
return true;
}
string vidSavePath;
FileStream fileStream = null;
bool success;
void Init()
{
vidSavePath = Path.Combine(Application.persistentDataPath, "Videos");
vidSavePath = Path.Combine(vidSavePath, "MyVideo.webm");
if (!Directory.Exists(Path.GetDirectoryName(vidSavePath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(vidSavePath));
}
try
{
fileStream = new FileStream(vidSavePath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
Debug.Log("File Successfully opened at" + vidSavePath.Replace("/", "\\"));
success = true;
}
catch (Exception e)
{
success = false;
Debug.LogError("Failed to Open File at Dir: " + vidSavePath.Replace("/", "\\") + "\r\n" + e.Message);
}
}
void AppendFile(byte[] buffer, int length)
{
if (success)
{
try
{
fileStream.Write(buffer, 0, length);
Debug.Log("Written data chunk to: " + vidSavePath.Replace("/", "\\"));
}
catch (Exception e)
{
success = false;
}
}
}
protected override void CompleteContent()
{
if (success)
Debug.Log("Done! Saved File to: " + vidSavePath.Replace("/", "\\"));
else
Debug.LogError("Failed to Save File to: " + vidSavePath.Replace("/", "\\"));
fileStream.Close();
}
protected override void ReceiveContentLength(int contentLength)
{
}
}
使用方法:
UnityWebRequest webRequest;
byte[] bytes = new byte[2000];
IEnumerator Start()
{
string url = "http://dl3.webmfiles.org/big-buck-bunny_trailer.webm";
webRequest = new UnityWebRequest(url);
webRequest.downloadHandler = new CustomWebRequest(bytes);
webRequest.SendWebRequest();
yield return webRequest;
}