看到别人封装好的一个下载工具类,支持断点续传,很好用,记录一下。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using UnityTools;
public class Downloader
{
private string url = null; // 需要下载的文件的地址
private string savePath = null; // 保存的路径
private UnityWebRequest request = null; // Unity中用来与Web服务器进行通信的类
private UnityTools.DownloadHandler downloadHandler = null; // 我们自己实现的下载处理类
private ErrorEventHandler onError = null; // 出错回调
private CompletedEventHandler onCompleted = null; // 完成回调
private ProgressEventHandler onProgress = null; // 进度回调
public Downloader(string url, string savePath, CompletedEventHandler onCompleted, ProgressEventHandler onProgress,
ErrorEventHandler onError)
{
this.url = url;
this.savePath = savePath;
this.onCompleted = onCompleted;
this.onProgress = onProgress;
this.onError = onError;
}
///
/// 开始下载
///
/// 超时时间(秒)
public void Start(int timeout = 600)
{
request = UnityWebRequest.Get(url);
if (!string.IsNullOrEmpty(savePath))
{
request.timeout = timeout;
request.disposeDownloadHandlerOnDispose = true;
downloadHandler = new UnityTools.DownloadHandler(savePath, onCompleted, onProgress, onError);
// 这里是设置http的请求头
// range表示请求资源的部分内容(不包括响应头的大小),单位是byte
request.SetRequestHeader("range", $"bytes={downloadHandler.CurrLength}-");
request.downloadHandler = downloadHandler;
}
request.SendWebRequest();
}
///
/// 清理
///
public void Dispose()
{
onError = null;
onCompleted = null;
onProgress = null;
if (request != null)
{
// 如果下载没有完成,就中止
if (!request.isDone)
request.Abort();
request.Dispose();
request = null;
}
}
}
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.Networking;
namespace UnityTools
{
public enum ErrorCode
{
DownloadContentEmpth,//需要下载的文件内容为空
TempFileMissing,//临时文件丢失
}
/// <summary>
/// 下载出错
/// </summary>
/// <param name="errorCode">错误码</param>
/// <param name="message">错误信息</param>
public delegate void ErrorEventHandler(ErrorCode errorCode, string message);
/// <summary>
/// 下载完成
/// </summary>
/// <param name="message">下载进度</param>
public delegate void CompletedEventHandler(string message);
/// <summary>
/// 下载进度
/// </summary>
/// <param name="prg">当前进度</param>
/// <param name="currLength">当前下载完成的长度</param>
/// <param name="totalLength">文件总长度</param>
public delegate void ProgressEventHandler(float prg, long currLength, long totalLength);
public class DownloadHandler : DownloadHandlerScript
{
private string savePath = null;//保存到的路径
private string tempPath = null;//下载临时文件路径
private long currLength = 0;//当前已经下载的数据长度
private long totalLength = 0; // 文件总数据长度
private long contentLength = 0; // 本次需要下载的数据长度
private FileStream fileStream = null; // 文件流,用来将接收到的数据写入文件
private ErrorEventHandler onError = null; // 出错回调
private CompletedEventHandler onCompleted = null; // 完成回调
private ProgressEventHandler onProgress = null; // 进度回调
public DownloadHandler(string savePath, CompletedEventHandler onCompleted, ProgressEventHandler onProgress, ErrorEventHandler onError)
{
this.savePath = savePath;
this.onCompleted = onCompleted;
this.onProgress = onProgress;
this.onError = onError;
this.tempPath = savePath + ".temp";
fileStream = new FileStream(tempPath, FileMode.OpenOrCreate, FileAccess.ReadWrite);
currLength = fileStream.Length;
fileStream.Position = currLength;
}
public long CurrLength
{
get { return currLength; }
}
public long TotalLength
{
get { return totalLength; }
}
/// <summary>
/// 在收到Content-Length标头调用的回调
/// </summary>
/// <param name="contentLength"></param>
protected override void ReceiveContentLengthHeader(ulong contentLength)
{
this.contentLength = (long)contentLength;
totalLength = this.contentLength + currLength;
}
/// <summary>
/// 从远程服务器收到数据时的回调
/// </summary>
/// <param name="data"></param>
/// <param name="dataLength"></param>
/// <returns></returns>
protected override bool ReceiveData(byte[] data, int dataLength)
{
//如果下载的数据长度小于等于0 就结束下载
if (contentLength <= 0 || data == null || data.Length <= 0)
{
return false;
}
fileStream.Write(data, 0, dataLength);
currLength += dataLength;
onProgress?.Invoke(currLength * 1.0f / totalLength, CurrLength, totalLength);
return true;
}
protected override void CompleteContent()
{
//接收完所有数据后,首先关闭文件流
Close();
//如果服务器上不存在该文件,请求下载的内容长度会为0
//所以需要特殊处理这种情况
if (contentLength <= 0)
{
onError(ErrorCode.DownloadContentEmpth, "下载内容长度为0");
return;
}
//如果下载完成后,临时问价你如果被意外删除了,也抛出错误提示
if (!File.Exists(tempPath))
{
onError(ErrorCode.TempFileMissing, "下载临时缓冲文件丢失");
return;
}
//如果下载的文件已经存在,就删除原文件
if (File.Exists(savePath))
{
File.Delete(savePath);
}
//通过以上的校验后,就将临时文件移动到目标路径下,下载成功
File.Move(tempPath, savePath);
onCompleted("下载文件完成");
}
public void Close()
{
if (fileStream == null) return;
fileStream.Close();
fileStream.Dispose();
fileStream = null;
}
}
}
使用方法:
//需要下载的地方这么使用
Downloader downloader = new Downloader(url, path, OnCompleted, OnProgress, OnError);
downloader.Start();
//以下是回调方法
private void OnProgress(float prg, long currLength, long totalLength)
{
Debug.LogFormat("下载进度{0:0.00}%,{1}M/{2}M", (prg * 100), currLength * 1.0f / 1024 / 1024,
totalLength * 1.0f / 1024 / 1024);
}
private void OnCompleted(string msg)
{
Debug.Log(msg);
}
private void OnError(ErrorCode code, string msg)
{
}