Новый ответ (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");
//Create Directory if it does not exist
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
был создан, но он не будет работать напрямую, потому что WWW
API сейчасреализован поверх UnityWebRequest
API в новейшей версии Unity, что означает, что если вы получите ошибку с WWW
API, вы также, вероятно, получите ту же ошибку с UnityWebRequest
.Даже если это работает, у вас, вероятно, будут проблемы на мобильных устройствах с таким небольшим ОЗУ, как Android.
Что нужно сделать, это использовать функцию UnityWebRequest DownloadHandlerScript
, которая позволяет загружать данныекускамиЗагружая данные порциями, вы можете предотвратить возникновение ошибки переполнения.API WWW
не реализовал эту функцию, поэтому UnityWebRequest
и DownloadHandlerScript
должны использоваться для загрузки данных в виде фрагментов.Вы можете прочитать, как это работает здесь .
Хотя это должно решить вашу текущую проблему, вы можете столкнуться с другой проблемой памяти при попытке сохранить эти большие данные с помощью File.WriteAllBytes
.Используйте FileStream
, чтобы выполнить сохранение, и закройте его только после завершения загрузки.
Создайте пользовательский UnityWebRequest
для загрузки данных по частям, как показано ниже:
using System;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
public class CustomWebRequest : DownloadHandlerScript
{
// Standard scripted download handler - will allocate memory on each ReceiveData callback
public CustomWebRequest()
: base()
{
}
// Pre-allocated scripted download handler
// Will reuse the supplied byte array to deliver data.
// Eliminates memory allocation.
public CustomWebRequest(byte[] buffer)
: base(buffer)
{
Init();
}
// Required by DownloadHandler base class. Called when you address the 'bytes' property.
protected override byte[] GetData() { return null; }
// Called once per frame when data has been received from the network.
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;
}
//Write the current data chunk to file
AppendFile(byteFromServer, dataLength);
return true;
}
//Where to save the video file
string vidSavePath;
//The FileStream to save the file
FileStream fileStream = null;
//Used to determine if there was an error while opening or saving the file
bool success;
void Init()
{
vidSavePath = Path.Combine(Application.persistentDataPath, "Videos");
vidSavePath = Path.Combine(vidSavePath, "MyVideo.webm");
//Create Directory if it does not exist
if (!Directory.Exists(Path.GetDirectoryName(vidSavePath)))
{
Directory.CreateDirectory(Path.GetDirectoryName(vidSavePath));
}
try
{
//Open the current file to write to
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
{
//Write the current data to the file
fileStream.Write(buffer, 0, length);
Debug.Log("Written data chunk to: " + vidSavePath.Replace("/", "\\"));
}
catch (Exception e)
{
success = false;
}
}
}
// Called when all data has been received from the server and delivered via ReceiveData
protected override void CompleteContent()
{
if (success)
Debug.Log("Done! Saved File to: " + vidSavePath.Replace("/", "\\"));
else
Debug.LogError("Failed to Save File to: " + vidSavePath.Replace("/", "\\"));
//Close filestream
fileStream.Close();
}
// Called when a Content-Length header is received from the server.
protected override void ReceiveContentLength(int contentLength)
{
//Debug.Log(string.Format("CustomWebRequest :: ReceiveContentLength - length {0}", contentLength));
}
}
Как сделатьиспользовать:
UnityWebRequest webRequest;
//Pre-allocate memory so that this is not done each time data is received
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;
}