XAsset 异步下载资源 解析
Posted 那个妹子留步
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了XAsset 异步下载资源 解析相关的知识,希望对你有一定的参考价值。
工具
资源服务器 hfs网络文件服务器(百度即可下载 hfs网络文件服务器(个人HTTP文件服务器)下载 v2.3 免费绿色版 - 比克尔下载 上传资源)
Unity
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using UnityEngine;
//namespace VEngine
//
public enum DownloadStatus
Wait,
Progressing,
Success,
Failed
public class DownloadInfo
public uint crc;
public string savePath;
public long size;
public string url;
public class DownLoadManager
/// <summary>
/// 最大同时下载数
/// </summary>
public static uint MaxDownLoads = 10;
/// <summary>
/// 读取速度
/// </summary>
public static uint ReadBufferSize = 1024 * 4;
/// <summary>
/// 准备 下载
/// </summary>
public static readonly List<Download> Prepared = new List<Download>();
/// <summary>
/// 正在 下载
/// </summary>
public static readonly List<Download> Progressing = new List<Download>();
/// <summary>
/// 缓存下载
/// </summary>
public static readonly Dictionary<string, Download> Cache = new Dictionary<string, Download>();
/// <summary>
/// 是否有正在下载的任务
/// </summary>
public static bool Working => Progressing.Count > 0;
//每秒下载速度
public static long TotalBandwidth get; private set;
/// <summary>
/// 总下载大小
/// </summary>
public static long TotalDownloadedBytes
get
var value = 0L;
foreach (var item in Cache) value += item.Value.downloadedBytes;
return value;
/// <summary>
/// 总大小
/// </summary>
public static long TotalSize
get
var value = 0L;
foreach (var item in Cache) value += item.Value.info.size;
return value;
private static float lastSampleTime;//最后下载时间
private static long lastTotalDownLoadedBytes;//最后下载字节数
public static bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain,
SslPolicyErrors spe)
return true;
public static void ClearAllDownloads()
foreach (var download in Progressing)
Prepared.Clear();
Progressing.Clear();
Cache.Clear();
public static Download DownloadAsync(string url,string savePath,long size = 0,uint crc = 0,Action<Download> complete=null)
return DownloadAsync(new DownloadInfo
url = url,
savePath = savePath,
crc = crc,
size = size
, complete);
public static Download DownloadAsync(DownloadInfo info, Action<Download> complete)
Download download;
if (!Cache.TryGetValue(info.url,out download))
download = new Download(info);
Prepared.Add(download);
Cache.Add(info.url, download);
else
UnityEngine.Debug.LogWarning($"Download url info.url already exist.");
if (complete != null)
download.completed += complete;
return download;
public static void UpdateAll()
//把准备下载列表的 加入正在下载的列表中
if (Prepared.Count > 0)
//取剩余可 准备下载数 受最大数量限制
for (int i = 0; i < Mathf.Min(Prepared.Count,MaxDownLoads - Progressing.Count); i++)
var download = Prepared[i];
Prepared.RemoveAt(i);
i--;
Progressing.Add(download);
download.Start();//启动下载
//刷新正在下载列表的 下载进度 和移除已经下载完毕的 任务
if (Progressing.Count > 0)
for (int index = 0; index < Progressing.Count; index++)
var download = Progressing[index];
if (download.updated != null) download.updated(download);
if (download.isDone)
if (download.status == DownloadStatus.Failed)
Debug.LogError($"Unable to download download.info.url with error download.error");
else
Debug.Log($"Success to download download.info.url");
Progressing.RemoveAt(index);
index--;
download.Complete();
//一秒间隔 刷新 进度
if (Time.realtimeSinceStartup - lastSampleTime >= 1)
lastTotalDownLoadedBytes = TotalDownloadedBytes;
lastSampleTime = Time.realtimeSinceStartup;
else
if (Cache.Count <= 0) return;
Cache.Clear();
lastTotalDownLoadedBytes = 0;
lastSampleTime = Time.realtimeSinceStartup;
public class Download : CustomYieldInstruction
public Action<Download> completed get; set;
public Action<Download> updated get; set;
/// <summary>
/// 下载状态
/// </summary>
public DownloadStatus status get; private set;
/// <summary>
/// 下载信息
/// </summary>
public DownloadInfo info get; private set;
private Thread _thread;
private FileStream writer;
private readonly byte[] _readBuffer = new byte[DownLoadManager.ReadBufferSize];
public bool isDone => status == DownloadStatus.Failed || status == DownloadStatus.Success;
public long downloadedBytes get; private set; //已经下载的字节数
public float process => downloadedBytes * 1f / info.size;//下载进度
public override bool keepWaiting =>!isDone;
public string error get; private set;
public Download(DownloadInfo info)
this.info = info;
status = DownloadStatus.Wait;
downloadedBytes = 0;
private WebRequest GetHttpWebRequest()
var httpWebRequest = (HttpWebRequest)WebRequest.Create(info.url) ;
httpWebRequest.ProtocolVersion = HttpVersion.Version10;
if (downloadedBytes > 0) httpWebRequest.AddRange(downloadedBytes);
return httpWebRequest;
private WebRequest CreateWebRequest()
WebRequest request;
if (info.url.StartsWith("https",StringComparison.OrdinalIgnoreCase))
ServicePointManager.ServerCertificateValidationCallback = DownLoadManager.CheckValidationResult;
request = GetHttpWebRequest();
return request;
private void DownLoading()
var request = CreateWebRequest();
using (var response = request.GetResponse())
if (response.ContentLength > 0)
//初始化下载文件 大小
if (info.size == 0) info.size = response.ContentLength + downloadedBytes;
using (var reader = response.GetResponseStream())
if (downloadedBytes < info.size)
while (status == DownloadStatus.Progressing)
if (ReadToEnd(reader)) break;
else
status = DownloadStatus.Success;
private bool ReadToEnd(Stream reader)
var len = reader.Read(_readBuffer, 0, _readBuffer.Length);
if (len > 0)
writer.Write(_readBuffer, 0, len);
downloadedBytes += len;
return false;
return true;
private void CloseWrite()
if (writer != null)
writer.Flush();
writer.Close();
private void Run()
try
DownLoading();//下载 和 写入
CloseWrite();
if (status == DownloadStatus.Failed) return;
//大小不匹配下载失败
if (downloadedBytes != info.size)
error = $"Download length downloadedBytes mismatch to info.size";
status = DownloadStatus.Failed;
return;
//CRC校验
if (info.crc != 0)
//var crc = Utility.ComputeCRC32(info.savePath);
//if (info.crc != crc)
//
// File.Delete(info.savePath);
// error = $"Download crc crc mismatch to info.crc";
// status = DownloadStatus.Failed;
// return;
//
status = DownloadStatus.Success;
catch (Exception e)
CloseWrite();
error = e.Message;
status = DownloadStatus.Failed;
public void Start()
//等待状态才会 启动
if (status != DownloadStatus.Wait) return;
Debug.Log($" start download info.url");
status = DownloadStatus.Progressing;
var file = new FileInfo(info.savePath);
//断点续传 还是怎么样
if (file.Exists && file.Length > 0)
if (info.size > 0 && file.Length == info.size)
status = DownloadStatus.Success;
return;
writer = File.OpenWrite(info.savePath);
downloadedBytes = writer.Length - 1;//只取了 -1长度
if (downloadedBytes > 0)
writer.Seek(-1, SeekOrigin.End);
else
var dir = Path.GetDirectoryName(info.savePath);
if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) Directory.CreateDirectory(dir);
writer = File.Create(info.savePath);
_thread = new Thread(Run)
IsBackground = true
;
_thread.Start();
public void Retry()
status = DownloadStatus.Wait;
Start();
public void Pause()
status = DownloadStatus.Wait;
public void UnPause()
Retry();
public void Cancel()
error = "User Cancel.";
status = DownloadStatus.Failed;
public void Complete()
if (completed != null)
completed.Invoke(this);
completed = null;
//
//测试下载
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
public class TestSomething : MonoBehaviour
[ContextMenu("SceneName")]
void Scene()
TempCopy();
public void TempCopy()
string path = @"D:\\testDownload\\dog.gif";
for (int i = 0; i < 100; i++)
CopyDirIntoDestDirectory(path, Path.Combine(@"D:\\testDownload",$"dogi.gif"), true);
public void CopyDirIntoDestDirectory(string sourceFileName, string destFileName, bool overwrite)
File.Copy(sourceFileName, destFileName, overwrite);
// Start is called before the first frame update
void Start()
TestXAssetDownload();
private Download download;
void TestXAssetDownload()
for (int i = 0; i < 30; i++)
var index = i;
DownLoadManager.DownloadAsync(new DownloadInfo()
savePath = Path.Combine(Application.dataPath, $"dogindex.gif"),
url = @"http://10.0.0.155:8000/" + $"dogindex.gif"
, (d) => print($"下载dogindex.gif完毕"); ); ;
// Update is called once per frame
void Update()
DownLoadManager.UpdateAll();
以上是关于XAsset 异步下载资源 解析的主要内容,如果未能解决你的问题,请参考以下文章
Unity2019 增量式GC(使用时间片段执行GC,减少卡顿)