IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> Unity 使用UnityWebRequest下载超大资源,实现断点续传和分段下载。 -> 正文阅读

[游戏开发]Unity 使用UnityWebRequest下载超大资源,实现断点续传和分段下载。

最近有个项目需要在服务器下载视频资源到本地,然后在本地播放视频,一开始看Unity官方文档找到资源下载的方法,但是在下载超大资源(一个2.8G的.mp4格式的视频)的时候回出现未知错误导致视频不能下载下来,先看官方提供的方法如下。

?

using System.Collections;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;

public class FileDownloader : MonoBehaviour {

    void Start () {
        StartCoroutine(DownloadFile());
    }

    IEnumerator DownloadFile() {
        var uwr = new UnityWebRequest("https://unity3d.com/", UnityWebRequest.kHttpVerbGET);
        string path = Path.Combine(Application.persistentDataPath, "unity3d.html");
        uwr.downloadHandler = new DownloadHandlerFile(path);
        yield return uwr.SendWebRequest();
        if (uwr.result != UnityWebRequest.Result.Success)
            Debug.LogError(uwr.error);
        else
            Debug.Log("File successfully downloaded and saved to " + path);
    }
}

于是我们采用断点续传和分段下载来实现超大资源的下载。

断点续传

户端软件断点续传指的是在下载或上传时,将下载或上传任务(一个文件或一个压缩包)人为的划分为几个部分,每一个部分采用一个线程进行上传或下载,如果碰到网络故障,可以从已经上传或下载的部分开始继续上传下载未完成的部分,而没有必要从头开始上传下载。用户可以节省时间,提高速度。

思路

获取到资源的总长度,获取到当前已经下载的长度,当下载中断再次请求下载的时候,先判断有没有下载完成,如果没有下载完成,从当前位置开始,下载剩下的资源。

GetResponseHeader("Content-Length")获取到资源的大小,下图中name=ueno&age=37正好是16个字节。这样我们就能获取到资源的总字节数。

SetRequestHeader("Range", "bytes=" + fileLength + "-")请求网络数据从第fileLength到最后的字节;

完整代码

代码注释已经比较详细

using System.Collections;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;

public class FileDownloader : MonoBehaviour
{
    public Text text;
    private string MyURL = "http://education.jnaw.top/lubozhibouploaded/quanjing/1615791915263.mp4";
    //private string MyURL = "http://education.jnaw.top/lubozhibouploaded/quanjing/1629796505018.mp4";
    //十亿字节为一段
    double loadedBytes = 1000000000;
    void Start()
    {
        Debug.Log(Application.persistentDataPath);

        StartCoroutine(BreakpointResume(MyURL, Application.persistentDataPath + "/MP4/1615791915263.mp4"));

    }

    /// <summary>
    /// 分段,断点下载文件
    /// </summary>
    /// <param name="loadPath">下载地址</param>
    /// <param name="savePath">保存路径</param>
    /// <returns></returns>
    IEnumerator BreakpointResume(string loadPath, string savePath)
    {
        //UnityWebRequest 经配置可传输 HTTP HEAD 请求的 UnityWebRequest。
        UnityWebRequest headRequest = UnityWebRequest.Head(loadPath);
        //开始与远程服务器通信。
        yield return headRequest.SendWebRequest();

        if (!string.IsNullOrEmpty(headRequest.error))
        {
            Debug.LogError("获取不到资源文件");
            yield break;
        }
        //获取文件总大小
        ulong totalLength = ulong.Parse(headRequest.GetResponseHeader("Content-Length"));
        Debug.Log("获取大小" + totalLength);
        headRequest.Dispose();
        UnityWebRequest Request = UnityWebRequest.Get(loadPath);
        //append设置为true文件写入方式为接续写入,不覆盖原文件。
        Request.downloadHandler = new DownloadHandlerFile(savePath, true);
        //创建文件
        FileInfo file = new FileInfo(savePath);
        //当前下载的文件长度
        ulong fileLength = (ulong)file.Length;

        //请求网络数据从第fileLength到最后的字节;
        Request.SetRequestHeader("Range", "bytes=" + fileLength + "-");

        if (!string.IsNullOrEmpty(Request.error))
        {
            Debug.LogError("下载失败" + Request.error);
        }
        if (fileLength < totalLength)
        {
            Request.SendWebRequest();
            while (!Request.isDone)
            {
                double progress = (Request.downloadedBytes + fileLength) / (double)totalLength;
                text.text = (progress * 100 + 0.01f).ToString("f2") + "%";
                // Debug.Log("下载量" + Request.downloadedBytes);
                //超过一定的字节关闭现在的协程,开启新的协程,将资源分段下载
                if (Request.downloadedBytes >= loadedBytes)
                {
                    StopCoroutine("BreakpointResume");

                    //如果 UnityWebRequest 在进行中,就停止。
                    Request.Abort();
                    if (!string.IsNullOrEmpty(Request.error))
                    {
                        Debug.LogError("下载失败" + Request.error);
                    }
                    yield return StartCoroutine(BreakpointResume(loadPath, savePath));
                }

               
                yield return null;
            }
        }
        if (string.IsNullOrEmpty(Request.error))
        {
            Debug.Log("下载成功" + savePath);
            text.text = "100%";
        }


      
        //表示不再使用此 UnityWebRequest,并且应清理它使用的所有资源。
        Request.Dispose();
    }
}

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-08-27 12:12:28  更:2021-08-27 12:13:08 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 0:51:11-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码