当前位置: 首页 > article >正文

Unity下载文件断点续下

使用方法:

 var request = UnityWebRequest.Get(“文件地址”);

DownloadHandlerFileRange  mCurrentDownloadHandler = new DownloadHandlerFileRange("文件保存的路径", request);
request.downloadHandler = mCurrentDownloadHandler;
//进度监听回调
 mCurrentDownloadHandler.DownloadedSizeUpdateEvent += DownLoadProgress;
yield return request.SendWebRequest();
 if (request.responseCode != 416 && !string.IsNullOrEmpty(request.error))
        {
            if ((request.result == UnityWebRequest.Result.ConnectionError || request.error != null))
            {
               
            }
            else if (request.result == UnityWebRequest.Result.ProtocolError)
            {

            }
        }
 
using UnityEngine.Networking;
using System.IO;
using System;
using UnityEngine;

/// <summary>
/// 使用方式:
/// UnityWebRequest unityWebRequest = new UnityWebRequest("url");
/// unityWebRequest.downloadHandler = new DownloadHandlerFileRange("文件保存的路径", unityWebRequest);
/// unityWebRequest.SendWebRequest();
/// </summary>
public class DownloadHandlerFileRange : DownloadHandlerScript
{
    /// <summary>
    /// 文件正式开始下载事件,此事件触发以后即可获取到文件的总大小
    /// </summary>
    public event System.Action StartDownloadEvent;

    /// <summary>
    /// ReceiveData()之后调用的回调,参数是本地文件已经下载的总大小
    /// </summary>
    public event System.Action<ulong> DownloadedSizeUpdateEvent;

    public event System.Action DownloadedEndEvent;
    /// <summary>
    /// 下载状态0:下载中,1:下载完成,2:解压中
    /// </summary>
    public int mDownLoadState = 0;

    #region 属性
    /// <summary>
    ///  下载速度,单位:KB/S 保留两位小数
    /// </summary>
    public float Speed
    {
        get
        {
            //kb/s
            return ((int)(DownloadSpeed / 1024 * 100)) / 100.0f;
            //return (((int)DownloadSpeed / 1024.0f) / 1024.0f) /*/ 100.0f*/;
        }
    }

    /// <summary>
    /// 文件的总大小
    /// </summary>
    public long FileSize
    {
        get
        {
            return TotalFileSize;
        }
    }

    /// <summary>
    /// 下载进度[0,1]
    /// </summary>
    public float DownloadProgress
    {
        get
        {
            return GetProgress();
        }
    }
    #endregion

    #region 公共方法
    /// <summary>
    /// 使用1MB的缓存,在补丁2017.2.1p1中对DownloadHandlerScript的优化中,目前最大传入数据量也仅仅是1024*1024,再多也没用
    /// </summary>
    /// <param name="path">文件保存的路径</param>
    /// <param name="request">UnityWebRequest对象,用来获文件大小,设置断点续传的请求头信息</param>
    public DownloadHandlerFileRange(string path, UnityWebRequest request) : base(new byte[1024 * 1024])
    {
        Debug.Log($"[Download] DownloadHandlerFileRange start");
        FilePath = path /*+ postfix*/;
        SavePath = Path.GetDirectoryName(path);
        //Debug.Log(FilePath);
        //Debug.Log(SavePath);
        mDownLoadState = 0;
        FileName = Path.GetFileNameWithoutExtension(path);
        FileStream = new FileStream(FilePath, FileMode.Append, FileAccess.Write);
        unityWebRequest = request;
        if (File.Exists(path))
        {
            LocalFileSize = new System.IO.FileInfo(path).Length;
        }
        CurFileSize = LocalFileSize;
        unityWebRequest.SetRequestHeader("Range", "bytes=" + LocalFileSize + "-");
        Debug.Log($"[Download] DownloadHandlerFileRange end LocalFileSize {LocalFileSize}");
    }

    /// <summary>
    /// 清理资源,该方法没办法重写,只能隐藏,如果想要强制中止下载,并清理资源(UnityWebRequest.Dispose()),该方法并不会被调用,这让人很苦恼
    /// </summary>
    public new void Dispose()
    {
        Debug.Log("[Download] Dispose()");
        Clean();
    }
    
    
    public void ManualDispose()
    {
        Debug.Log("[Download] ManualDispose()");
        Clean();
    }

    public void RemoveFolder()
    {
        unityWebRequest.Dispose();

        if (FileStream != null)
        {
            FileStream.Flush();
            FileStream.Dispose();
            FileStream = null;
        }
        if (Directory.Exists(SavePath))
        {
            Directory.Delete(SavePath,true);
        }
        if (File.Exists(FilePath))
            File.Delete(FilePath);
    }

    public void CloceUnityWebRequest()
    {
        unityWebRequest.Dispose();
    }

    /// <summary>
    /// 改名
    /// </summary> 
    private void ChangeName()
    {
        string filepathName = SavePath + "/" + FileName;
        if (File.Exists(filepathName))
            File.Delete(filepathName);
        File.Move(FilePath, filepathName);
    }
    #endregion

    #region 私有方法
    /// <summary>
    /// 关闭文件流
    /// </summary>
    private void Clean()
    {
        Debug.Log("[Download] Clean()");
        DownloadSpeed = 0.0f;
        if (FileStream != null)
        {
            FileStream.Flush();
            FileStream.Dispose();
            FileStream = null;
        }
        StartDownloadEvent = null;
        DownloadedSizeUpdateEvent = null;
    }
    #endregion

    #region 私有继承的方法
    /// <summary>
    /// 下载完成后清理资源
    /// </summary>
    protected override void CompleteContent()
    {
        Debug.Log("[Download] CompleteContent()");
        DownloadedEndEvent?.Invoke();
        mDownLoadState = 1;
        base.CompleteContent();
        Clean();
        //ChangeName();
    }

    /// <summary>
    /// 调用UnityWebRequest.downloadHandler.data属性时,将会调用该方法,用于以byte[]的方式返回下载的数据,目前总是返回null
    /// </summary>
    /// <returns></returns>
    protected override byte[] GetData()
    {
        Debug.Log("[Download] GetData()");
        return null;
    }

    /// <summary>
    /// 调用UnityWebRequest.downloadProgress属性时,将会调用该方法,用于返回下载进度
    /// </summary>
    /// <returns></returns>
    protected override float GetProgress()
    {
        return TotalFileSize == 0 ? 0 : ((float)CurFileSize) / TotalFileSize;
    }

    /// <summary>
    /// 调用UnityWebRequest.downloadHandler.text属性时,将会调用该方法,用于以string的方式返回下载的数据,目前总是返回null
    /// </summary>
    /// <returns></returns>
    protected override string GetText()
    {
        return null;
    }

    //Note:当下载的文件数据大于2G时,该int类型的参数将会数据溢出,所以先自己通过响应头来获取长度,获取不到再使用参数的方式
    [System.Obsolete]
    protected override void ReceiveContentLength(int contentLength)
    {
        Debug.Log($"[Download] ReceiveContentLength {contentLength}");
        string contentLengthStr = unityWebRequest.GetResponseHeader("Content-Length");
        
        if (!string.IsNullOrEmpty(contentLengthStr))
        {
            try
            {
                TotalFileSize = long.Parse(contentLengthStr);
            }
            catch (System.FormatException e)
            {
                UnityEngine.Debug.Log("获取文件长度失败,contentLengthStr:" + contentLengthStr + "," + e.Message);
                TotalFileSize = contentLength;
            }
            catch (System.Exception e)
            {
                UnityEngine.Debug.Log("获取文件长度失败,contentLengthStr:" + contentLengthStr + "," + e.Message);
                TotalFileSize = contentLength;
            }
        }
        else
        {
            TotalFileSize = contentLength;
        }
        //这里拿到的下载大小是待下载的文件大小,需要加上本地已下载文件的大小才等于总大小
        TotalFileSize += LocalFileSize;
        LastTime = UnityEngine.Time.time;
        LastDataSize = CurFileSize;
        if (StartDownloadEvent != null)
        {
            StartDownloadEvent();
        }
        mDownLoadState = 0;
    }

    //在2017.3.0(包括该版本)以下的正式版本中存在一个性能上的问题
    //该回调方法有性能上的问题,每次传入的数据量最大不会超过65536(2^16)个字节,不论缓存区有多大
    //在下载速度中的体现,大约相当于每秒下载速度不会超过3.8MB/S
    //这个问题在 "补丁2017.2.1p1" 版本中被优化(2017.12.21发布)(https://unity3d.com/cn/unity/qa/patch-releases/2017.2.1p1)
    //(965165) - Web: UnityWebRequest: improve performance for DownloadHandlerScript.
    //优化后,每次传入数据量最大不会超过1048576(2^20)个字节(1MB),基本满足下载使用
    protected override bool ReceiveData(byte[] data, int dataLength)
    {
        if (data == null || dataLength == 0 || unityWebRequest.responseCode > 400)
        {
            Debug.Log($"[Download] ReceiveData return false: data: {data} length: {dataLength} responseCode: {unityWebRequest.responseCode}");
            return false;
        }
        if (FileStream == null)
        {
            return false;
        }
        FileStream.Write(data, 0, dataLength);
        CurFileSize += dataLength;
        //统计下载速度
        if (UnityEngine.Time.time - LastTime >= 1.0f)
        {
            DownloadSpeed = (CurFileSize - LastDataSize) / (UnityEngine.Time.time - LastTime);
            LastTime = UnityEngine.Time.time;
            LastDataSize = CurFileSize;
        }
        //Debug.Log("DownloadSpeed:" + DownloadSpeed);
        DownloadedSizeUpdateEvent?.Invoke((ulong)CurFileSize);
        
        return true;
    }

    ~DownloadHandlerFileRange()
    {
        Debug.Log("[Download] ~DownloadHandlerFileRange()");
        Clean();
    }
    #endregion

    #region 私有字段
    private string FilePath;//文件保存的路径 带文件名称
    private string SavePath;//文件保存的路径 不带文件名称
    private string FileName;//文件名称
    private string postfix = ".temp"; //临时文件后缀名
    private FileStream FileStream;
    private UnityWebRequest unityWebRequest;
    private long LocalFileSize = 0;//本地已经下载的文件的大小
    private long TotalFileSize = 0;//文件的总大小
    private long CurFileSize = 0;//当前的文件大小
    private float LastTime = 0;//用作下载速度的时间统计
    private float LastDataSize = 0;//用来作为下载速度的大小统计
    private float DownloadSpeed = 0;//下载速度,单位:Byte/S
    #endregion
}

http://www.kler.cn/a/420706.html

相关文章:

  • Flink四大基石之State(状态) 的使用详解
  • 解决 Flutter Dio合并请求多个接口,如果一个接口500,那么导致其他请求不在执行
  • Linux 定时任务 命令解释 定时任务格式详解
  • 【网络】协议与网络传输
  • Android 编译和使用libheif
  • C++之异常智能指针其他
  • K8S疑难概念理解——Pod,应该以哪种Kind来部署应用,为什么不直接Pod这种kind?
  • 【Elasticsearch】04-RestAPI
  • 深度学习常用训练命令解释
  • 在线家具商城基于 SpringBoot:设计模式与实现方法探究
  • vue中v-for的细节
  • 02appdesigner学习记录
  • Kafka怎么发送JAVA对象并在消费者端解析出JAVA对象--示例
  • Flutter的文字高度及行高简单计算
  • 智能探针技术:实现可视、可知、可诊的主动网络运维策略
  • 基于SSM超市商品管理系统JAVA|VUE|Springboot计算机毕业设计源代码+数据库+LW文档+开题报告+答辩稿+部署教+代码讲解
  • 如何运用Python爬虫快速获得1688商品详情数据
  • Spring MVC接收前台信息,并在页面返回
  • 人工智能-深度学习-BP算法
  • 【计算机网络】实验3:集线器和交换器的区别及交换器的自学习算法
  • mysql之慢查询设置及日志分析
  • Paper -- 建筑物高度估计 -- 使用街景图像、深度学习、轮廓处理和地理空间数据的建筑高度估计
  • React.memo 和useMemo 的区别
  • Python 调用 Umi-OCR API 批量识别图片/PDF文档数据
  • 【前端】小程序实现预览pdf并导出
  • Argon2-cffi:Python中的密码学哈希库