unity 下载文件 断点续传

本文介绍了如何创建一个基类DownloadItem,用于管理下载任务,重点讲解了HTTP下载项(HttpDownloadItem)的实现,包括支持断点续传的逻辑。通过实例展示了如何创建下载项并使用其功能,如检查URL、路径、下载进度和文件操作。
摘要由CSDN通过智能技术生成

基类

首先先创建一个基类,里面存放下载需要的一些数据,例如文件url,下载存放路径等等。

public abstract class DownloadItem {
 
    /// <summary>
    /// 网络资源url路径
    /// </summary>
    protected string m_srcUrl;
    /// <summary>
    /// 资源下载存放路径,不包含文件名
    /// </summary>
    protected string m_savePath;
    /// <summary>
    /// 文件名,不包含后缀
    /// </summary>
    protected string m_fileNameWithoutExt;
    /// <summary>
    /// 文件后缀
    /// </summary>
    protected string m_fileExt;
    /// <summary>
    /// 下载文件全路径,路径+文件名+后缀
    /// </summary>
    protected string m_saveFilePath;
    /// <summary>
    /// 原文件大小
    /// </summary>
    protected long m_fileLength;
    /// <summary>
    /// 当前下载好了的大小
    /// </summary>
    protected long m_currentLength;
    /// <summary>
    /// 是否开始下载
    /// </summary>
    protected bool m_isStartDownload;
    public bool isStartDownload {
        get {
            return m_isStartDownload;
        }
    }
 
    public DownloadItem(string url, string path) {
        m_srcUrl = url;
        m_savePath = path;
        m_isStartDownload = false;
        m_fileNameWithoutExt = Path.GetFileNameWithoutExtension(m_srcUrl);
        m_fileExt = Path.GetExtension(m_srcUrl);
        m_saveFilePath = string.Format("{0}/{1}{2}", m_savePath, m_fileNameWithoutExt, m_fileExt);
    }
 
    /// <summary>
    /// 开始下载
    /// </summary>
    /// <param name="callback">下载完成回调</param>
    public virtual void StartDownload(Action callback = null) {
        if(string.IsNullOrEmpty(m_srcUrl) || string.IsNullOrEmpty(m_savePath)) {
            return;
        }
        //若存放目录不存在则创建目录
        FileTool.CreateDirectory(m_saveFilePath);
    }
 
    /// <summary>
    /// 获取下载进度
    /// </summary>
    /// <returns>进度,0-1</returns>
    public abstract float GetProcess();
 
    /// <summary>
    /// 获取当前下载了的文件大小
    /// </summary>
    /// <returns>当前文件大小</returns>
    public abstract long GetCurrentLength();
 
    /// <summary>
    /// 获取要下载的文件大小
    /// </summary>
    /// <returns>文件大小</returns>
    public abstract long GetLength();
 
    public abstract void Destroy();
}

HTTP

这种方式下载,我们采用的是边读取边生成对应文件,适合较大文件下载。关于断点续传的处理,我们下载的时候,先根据读取的内容生成一个临时文件,当全部下载好后,才将这个临时文件转换成正式的文件名。若中途下载中断,已下载好的那部分文件依据在对应目录下,我们下次下载可以直接在上次下载的临时文件后添加内容。

所以下载逻辑就是,每次下载先判断是否有对应的临时文件,若没有则是第一次下载,从初始位置读取下载,若有该文件,则读取该文件信息,获取文件大小当之后的读取下载的偏移量,从当前位置开始下载,直至下载完成。

/// <summary>
/// HTTP的方式下载,支持断点续传
/// </summary>
public class HttpDownloadItem : DownloadItem {
    /// <summary>
    /// 临时文件后缀名
    /// </summary>
    string m_tempFileExt = ".temp";
    /// <summary>
    /// 临时文件全路径
    /// </summary>
    string m_tempSaveFilePath;
 
    public HttpDownloadItem(string url, string path) : base(url, path) {
        m_tempSaveFilePath = string.Format("{0}/{1}{2}", m_savePath, m_fileNameWithoutExt, m_tempFileExt);
    }
 
    public override void StartDownload(Action callback = null) {
        base.StartDownload();
        UICoroutine.uiCoroutine.StartCoroutine(Download(callback));
    }
 
    IEnumerator Download(Action callback = null) {
        HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(m_srcUrl);
        request.Method = "GET";
 
        FileStream fileStream;
        if(File.Exists(m_tempSaveFilePath)) {
            //若之前已下载了一部分,继续下载
            fileStream = File.OpenWrite(m_tempSaveFilePath);
            m_currentLength = fileStream.Length;
            fileStream.Seek(m_currentLength, SeekOrigin.Current);
 
            //设置下载的文件读取的起始位置
            request.AddRange((int)m_currentLength);
        } else {
            //第一次下载
            fileStream = new FileStream(m_tempSaveFilePath, FileMode.Create, FileAccess.Write);
            m_currentLength = 0;
        }
 
        HttpWebResponse response = (HttpWebResponse)request.GetResponse();
        Stream stream = response.GetResponseStream();
        //总的文件大小=当前需要下载的+已下载的
        m_fileLength = response.ContentLength + m_currentLength;
 
        m_isStartDownload = true;
        int lengthOnce;
        int bufferMaxLength = 1024 * 20;
 
        while(m_currentLength < m_fileLength) {
 
            byte[] buffer = new byte[bufferMaxLength];
            if(stream.CanRead) {
                //读写操作
                lengthOnce = stream.Read(buffer, 0, buffer.Length);
                m_currentLength += lengthOnce;
                fileStream.Write(buffer, 0, lengthOnce);
            } else {
                break;
            }
            yield return null;
        }
 
        m_isStartDownload = false;
        response.Close();
        stream.Close();
        fileStream.Close();
 
        //临时文件转为最终的下载文件
        File.Move(m_tempSaveFilePath, m_saveFilePath);
 
        if(callback != null) {
            callback();
        }
    }
 
    public override float GetProcess() {
        if(m_fileLength > 0) {
            return Mathf.Clamp((float)m_currentLength / m_fileLength, 0, 1);
        }
        return 0;
    }
 
    public override long GetCurrentLength() {
        return m_currentLength;
    }
 
    public override long GetLength() {
        return m_fileLength;
    }
 
    public override void Destroy() {
    }
}

补充

上述代码用到了两个自定义的方法FileTool.CreateDirectory()和FileTool.CreatFile(),内容很简单,如下

public class FileTool {
 
    /// <summary>
    /// 创建目录
    /// </summary>
    /// <param name="filePath">需要创建的目录路径</param>
    public static void CreateDirectory(string filePath) {
        if(!string.IsNullOrEmpty(filePath)) {
            string dirName = Path.GetDirectoryName(filePath);
            if(!Directory.Exists(dirName)) {
                Directory.CreateDirectory(dirName);
            }
        }
    }
 
    /// <summary>
    /// 创建文件
    /// </summary>
    /// <param name="filePath">文件路径</param>
    /// <param name="bytes">文件内容</param>
    public static void CreatFile(string filePath, byte[] bytes) {
        FileInfo file = new FileInfo(filePath);
        Stream stream = file.Create();
 
        stream.Write(bytes, 0, bytes.Length);
 
        stream.Close();
        stream.Dispose();
    }
}

UICoroutine相关的代码,深表歉意。UICoroutine在这个例子中的作用其实就是场景中新建一个GameObject,专门用来启用协程,因为前面的几个类没有继承于MonoBehaviour,所以无法直接调用StartCoroutine方法

public class UICoroutine : MonoBehaviour {
    private static UICoroutine mInstance = null;
 
    public static UICoroutine uiCoroutine {
        get {
            if(mInstance == null) {
                GameObject go = new GameObject();
                if(go != null) {
                    go.name = "_UICoroutine";
                    go.AddComponent<UICoroutine>();
                } else {
                    Debug.LogError("Init UICoroutine faild. GameObjet can not be null.");
                }
            }
            return mInstance;
        }
    }
 
    void Awake() {
        DontDestroyOnLoad(gameObject);
        mInstance = this;
    }
 
    void OnDestroy() {
        mInstance = null;
    }
}

使用

public class DownloadDemo : MonoBehaviour {
 
    DownloadItem m_item;
    string testScrUrl = "http://dlsw.baidu.com/sw-search-sp/soft/ca/13442/Thunder_dl_7.9.42.5050.1449557123.exe";
    int count = 0;
 
    void Start() {
        Debug.Log(Application.persistentDataPath);
 
        //m_item = new WWWDownloadItem(testScrUrl, Application.persistentDataPath);
        //m_item.StartDownload(DownloadFinish);
 
        m_item = new HttpDownloadItem(testScrUrl, Application.persistentDataPath);
        m_item.StartDownload(DownloadFinish);
    }
 
    void Update() {
        count++;
 
        if(count % 20 == 0) {
            if(m_item != null && m_item.isStartDownload) {
                Debug.Log("下载进度------" + m_item.GetProcess() + "------已下载大小---" + m_item.GetCurrentLength());
            }
        }
    }
 
    void DownloadFinish() {
        Debug.Log("DownloadFinish!!!");
    }
}

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity 是一款跨平台的游戏开发引擎,它提供了丰富的功能和工具来帮助开发者创建高质量的游戏。其中一个功能就是并发下载。 并发下载是指同时下载多个文件或资源的能力。在游戏开发中,有时候需要下载大量的资源文件,包括纹理、模型、声音等等。如果采用串行下载的方式,即一个文件下载完后再下载下一个文件,会极大地拖慢整个下载过程,影响游戏的加载速度和用户体验。 Unity 提供了并发下载的功能,使得开发者可以同时下载多个文件,加快下载速度。开发者可以通过使用 Unity 提供的网络API(例如UnityWebRequest类)来实现并发下载。使用这些API,可以同时发起多个下载请求,而不需要等待前一个请求完成。 通过并发下载,可以实现资源的异步加载。开发者可以在游戏启动时开始下载游戏所需的资源,而不需要等待下载完成才能开始游戏。这样可以极大地减少游戏的加载时间,提高玩家的初次加载体验。 此外,Unity 还提供了一些优化方法来进一步提高并发下载的效果。例如,可以使用压缩算法对资源进行压缩,减小资源文件的大小,从而加快下载速度。还可以使用断点续传机制,即在下载中断后,可以从上次下载的位置继续下载,避免重新下载整个文件。 综上所述,Unity 的并发下载功能可以帮助开发者加快游戏资源的下载速度,提高游戏加载的效率,从而改善用户体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值