下载大文件

通过使用UnityEngine.WWW下载文件,我收到错误

OverflowException:Number overflow。

我发现错误是由结构本身引起的,因为字节数组的字节数多于int.MaxValue可以分配(~2GB)。

通过使用www.bytes返回数组来触发错误,这意味着框架可能以其他方式存储数组。

如何以其他方式访问下载的数据,还是有更大的文件替代?

 public IEnumerator downloadFile() { WWW www = new WWW(filesource); while(!www.isDone) { progress = www.progress; yield return null; } if(string.IsNullOrEmpty(www.error)) { data = www.bytes; // <- Errormessage fired here } } 

新答案(Unity 2017.2及以上版本)

UnityWebRequestDownloadHandlerFile UnityWebRequest使用。 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现在在最新版本的Unity中的UnityWebRequest API之上实现,这意味着如果你在WWW API上出错,你也会可能会在UnityWebRequest遇到同样的错误。 即使它有效,你也可能会在像Android这样的小型内存移动设备上遇到问题。

该怎么做是使用UnityWebRequest的DownloadHandlerScriptfunction,它允许您以块的forms下载数据。 通过以块的forms下载数据,可以防止导致溢出错误。 WWW API未实现此function,因此必须使用UnityWebRequestDownloadHandlerScript以块的forms下载数据。 你可以在这里阅读它是如何工作的。

虽然这应该可以解决您当前的问题,但在尝试使用File.WriteAllBytes保存大型数据时可能会遇到另一个内存问题。 使用FileStream执行保存部分,仅在下载完成后关闭它。

创建一个自定义的UnityWebRequest用于以块的forms下载数据,如下所示:

 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; }