Скачать большой файл - PullRequest
       1

Скачать большой файл

0 голосов
/ 05 июня 2018

Загружая файл с UnityEngine.WWW, я получаю ошибку

OverflowException: переполнение номера.

Я обнаружил, что ошибка вызвана самой структурой, поскольку байтовый массив имеет больше байтов, чем может выделить int.MaxValue (~ 2 ГБ).

Ошибка вызывается возвращением массива с 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
    }
}

1 Ответ

0 голосов
/ 05 июня 2018

Новый ответ (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;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...