mirror of
https://github.com/Alex-Rachel/TEngine.git
synced 2025-08-14 16:51:28 +00:00
Hot Update DownLoader
Hot Update DownLoader
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
using System.IO;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
namespace TEngine
|
||||
{
|
||||
public class DownloadHandlerFileRange : DownloadHandlerScript, IDownload
|
||||
{
|
||||
private readonly string _url;
|
||||
private string _path;
|
||||
private string _md5;
|
||||
private FileStream _fileStream;
|
||||
private UnityWebRequest _unityWebRequest;
|
||||
|
||||
private long _totalFileSize = 0;
|
||||
private long _curFileSize = 0;
|
||||
public bool HasError { get; private set; }
|
||||
protected BackgroundDownloadStatus _status = BackgroundDownloadStatus.NotBegin;
|
||||
|
||||
private DownloadImpl _imp;
|
||||
|
||||
public void SetImp(DownloadImpl imp)
|
||||
{
|
||||
_imp = imp;
|
||||
}
|
||||
|
||||
public DownloadHandlerFileRange(string url, string path, long totalLength, string md5) : base(new byte[1024 * 1024])
|
||||
{
|
||||
TLogger.LogInfo($"DownloadHandlerFileRange url:{url},path:{path},totalLength:{totalLength}");
|
||||
|
||||
_url = url;
|
||||
_path = path;
|
||||
_md5 = md5;
|
||||
|
||||
var dirPath = Path.GetDirectoryName(_path);
|
||||
if (dirPath != null)
|
||||
{
|
||||
TLogger.LogInfo($"DownloadHandlerFileRange dirPath:{dirPath}");
|
||||
if (!Directory.Exists(dirPath))
|
||||
{
|
||||
Directory.CreateDirectory(dirPath);
|
||||
}
|
||||
}
|
||||
|
||||
_totalFileSize = totalLength;
|
||||
_status = BackgroundDownloadStatus.NotBegin;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 兼容断点续传
|
||||
/// </summary>
|
||||
public void StartDownload()
|
||||
{
|
||||
if (_status != BackgroundDownloadStatus.NotBegin)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var index = _path.IndexOf("_md5_");
|
||||
var fileMd5 = string.Empty;
|
||||
if (File.Exists(_path))
|
||||
{
|
||||
fileMd5 = LoaderUtilities.GetMd5Hash(_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (index >= 0)
|
||||
{
|
||||
fileMd5 = LoaderUtilities.GetMd5Hash(_path.Substring(0, index));
|
||||
}
|
||||
}
|
||||
|
||||
if (fileMd5 == _md5)
|
||||
{
|
||||
_status = BackgroundDownloadStatus.Done;
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_fileStream = new FileStream(_path, FileMode.OpenOrCreate, FileAccess.Write);
|
||||
var localFileSize = _fileStream.Length;
|
||||
_fileStream.Seek(localFileSize, SeekOrigin.Begin);
|
||||
_curFileSize = localFileSize;
|
||||
_unityWebRequest = UnityWebRequest.Get(_url);
|
||||
_unityWebRequest.SetRequestHeader("Range", "bytes=" + localFileSize + "-" + _totalFileSize);
|
||||
_unityWebRequest.downloadHandler = this;
|
||||
_unityWebRequest.SendWebRequest();
|
||||
|
||||
_status = BackgroundDownloadStatus.Downloading;
|
||||
}
|
||||
catch (System.Exception e)
|
||||
{
|
||||
TLogger.LogError($"DownloadHandlerFileRange.StartDownload,Exception,{e.StackTrace}");
|
||||
_status = BackgroundDownloadStatus.Failed;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
public new void Dispose()
|
||||
{
|
||||
if (_status == BackgroundDownloadStatus.Downloading)
|
||||
{
|
||||
_status = BackgroundDownloadStatus.Failed;
|
||||
}
|
||||
|
||||
base.Dispose();
|
||||
|
||||
if (_fileStream != null)
|
||||
{
|
||||
_fileStream.Close();
|
||||
_fileStream.Dispose();
|
||||
_fileStream = null;
|
||||
}
|
||||
|
||||
if (_unityWebRequest != null)
|
||||
{
|
||||
_unityWebRequest.Abort();
|
||||
_unityWebRequest.Dispose();
|
||||
_unityWebRequest = null;
|
||||
}
|
||||
}
|
||||
#region
|
||||
public float Progress => _totalFileSize == 0 ? 0 : ((float)_curFileSize) / _totalFileSize;
|
||||
|
||||
public long TotalSize => _totalFileSize;
|
||||
|
||||
public long CurrentSize => _curFileSize;
|
||||
|
||||
protected override bool ReceiveData(byte[] data, int dataLength)
|
||||
{
|
||||
if (data == null || dataLength <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
_fileStream.Write(data, 0, dataLength);
|
||||
_fileStream.Flush();
|
||||
_curFileSize += dataLength;
|
||||
LoadUpdateLogic.Instance.Down_Progress_Action?.Invoke(_curFileSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
#region IEnumerator
|
||||
public object Current
|
||||
{
|
||||
get
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public BackgroundDownloadStatus Status => _status;
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (_status == BackgroundDownloadStatus.Done ||
|
||||
_status == BackgroundDownloadStatus.Failed ||
|
||||
_status == BackgroundDownloadStatus.NetworkError)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_unityWebRequest.isNetworkError || _unityWebRequest.isHttpError)
|
||||
{
|
||||
_status = BackgroundDownloadStatus.NetworkError;
|
||||
}
|
||||
else if (_unityWebRequest.isDone)
|
||||
{
|
||||
_status = BackgroundDownloadStatus.Done;
|
||||
}
|
||||
|
||||
return _status == BackgroundDownloadStatus.Downloading;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{ }
|
||||
#endregion
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 13ec5fbe4e3143e479b624eac7b1431e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
299
Assets/TEngine/Runtime/HotUpdate/Runtime/DownloadImpl.cs
Normal file
299
Assets/TEngine/Runtime/HotUpdate/Runtime/DownloadImpl.cs
Normal file
@@ -0,0 +1,299 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace TEngine
|
||||
{
|
||||
/// <summary>
|
||||
/// 下载状态
|
||||
/// </summary>
|
||||
public enum BackgroundDownloadStatus
|
||||
{
|
||||
NotBegin = 0, //未开始
|
||||
Downloading = 1, //下载中
|
||||
NetworkError = 2, //网络变化
|
||||
Done = 3, //下载完成
|
||||
Failed = 4, //下载失败
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 资源加载过程中的状态
|
||||
/// </summary>
|
||||
public enum DownLoadResult
|
||||
{
|
||||
StartDownLoad = 0, //开始下载
|
||||
HeadRequestFail = 1, //请求头失败
|
||||
DownLoadRequestFail = 2, //现在请求失败
|
||||
AreadyDownLoaded = 3, //已经下载过而且下载好了
|
||||
DownLoading = 4, //下载中
|
||||
NetChanged = 5,
|
||||
DownLoaded = 6, //下载完成
|
||||
DownLoadingError = 7,//接收数据的那个过程中出错
|
||||
HeadRequestError = 8,//获取下载包大小报错
|
||||
ReceiveNullData = 9,//接受到空数据
|
||||
DownError = 10,//数据没有接受完但是isDone为true
|
||||
ReceiveError = 11,//接收数据失败
|
||||
Md5Wrong = 12,//md5错误
|
||||
AllDownLoaded = 13//全部下载完成
|
||||
}
|
||||
|
||||
public class DownloadImpl
|
||||
{
|
||||
private List<LoadResource> _files;
|
||||
private string _path;
|
||||
private Action<int, List<LoadResource>> _callback = null;
|
||||
private long _totalFileSize = 0;
|
||||
private long _downLoadedSize = 0;
|
||||
private long _currentLoadSize = 0;
|
||||
|
||||
private float _last_record_time = 0f;
|
||||
private float _last_record_process = 0f;
|
||||
private long _speed = 0;
|
||||
|
||||
IDownload _downloader = null;
|
||||
|
||||
public DownloadImpl(List<LoadResource> files, string path, Action<int, List<LoadResource>> callback)
|
||||
{
|
||||
_files = files;
|
||||
_path = path;
|
||||
_callback = callback;
|
||||
_downLoadedSize = 0;
|
||||
_totalFileSize = 0;
|
||||
foreach (var item in files)
|
||||
{
|
||||
_totalFileSize += item.Size;
|
||||
}
|
||||
|
||||
var dirPath = Path.GetDirectoryName(_path);
|
||||
if (dirPath != null)
|
||||
{
|
||||
if (!Directory.Exists(dirPath))
|
||||
{
|
||||
Directory.CreateDirectory(dirPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator DownLoad()
|
||||
{
|
||||
_downLoadedSize = 0;
|
||||
bool result = false;
|
||||
foreach (var item in _files)
|
||||
{
|
||||
string remoteUrl = item.RemoteUrl + "?" + GameConfig.Instance.GameBundleVersion;
|
||||
Callback(DownLoadResult.StartDownLoad);
|
||||
_downloader = GetDownloader(remoteUrl, _path + item.Url, item.Size, item.Md5, this);
|
||||
_downloader.StartDownload();
|
||||
yield return _downloader;
|
||||
|
||||
if (_downloader != null)
|
||||
{
|
||||
_downloader.Dispose();
|
||||
result = _DealWithDownLoadOk(DownLoadResult.DownLoaded, _downloader.Status, item);
|
||||
if (result == false)
|
||||
{
|
||||
yield break;
|
||||
}
|
||||
|
||||
if (_downloader.Status == BackgroundDownloadStatus.Done)
|
||||
{
|
||||
_downLoadedSize += item.Size;
|
||||
}
|
||||
}
|
||||
yield return null;
|
||||
}
|
||||
|
||||
if (result)
|
||||
{
|
||||
_DownLoaded(_files);
|
||||
}
|
||||
}
|
||||
|
||||
void _DownLoaded(List<LoadResource> list)
|
||||
{
|
||||
Callback(DownLoadResult.AllDownLoaded, list);
|
||||
}
|
||||
|
||||
bool _DealWithDownLoadOk(DownLoadResult downloadType, BackgroundDownloadStatus status, LoadResource data)
|
||||
{
|
||||
string fileLocalPath = _path + data.Url;
|
||||
|
||||
if (status == BackgroundDownloadStatus.NetworkError)
|
||||
{
|
||||
Callback(DownLoadResult.NetChanged);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (status == BackgroundDownloadStatus.Failed)
|
||||
{
|
||||
LoaderUtilities.DeleteFile(fileLocalPath);
|
||||
TLogger.LogError("DownloaderImpl._DownLoaded, Load failed");
|
||||
Callback(DownLoadResult.ReceiveError);
|
||||
return false;
|
||||
}
|
||||
|
||||
int index = fileLocalPath.IndexOf("_md5_");
|
||||
var tempMd5 = LoaderUtilities.GetMd5Hash(fileLocalPath);
|
||||
if (index >= 0)
|
||||
{
|
||||
var fileInfo = new FileInfo(fileLocalPath);
|
||||
string newFilename = fileLocalPath.Substring(0, index);
|
||||
if (tempMd5 == data.Md5)
|
||||
{
|
||||
if (File.Exists(newFilename))
|
||||
{
|
||||
File.Delete(newFilename);
|
||||
}
|
||||
|
||||
fileInfo.MoveTo(newFilename);
|
||||
Callback(downloadType);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (File.Exists(newFilename))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
TLogger.LogError($"DownloaderImpl._DownLoaded, Current md5:{tempMd5},Target md5:{data.Md5} not match,path:{data.Url}");
|
||||
LoaderUtilities.DeleteFile(fileLocalPath);
|
||||
Callback(DownLoadResult.Md5Wrong);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tempMd5 == data.Md5)
|
||||
{
|
||||
Callback(downloadType);
|
||||
}
|
||||
else
|
||||
{
|
||||
TLogger.LogError($"DownloaderImpl._DownLoaded, Current md5:{tempMd5},Target md5:{data.Md5} not match,path:{data.Url}");
|
||||
LoaderUtilities.DeleteFile(fileLocalPath);
|
||||
Callback(DownLoadResult.Md5Wrong);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Callback(DownLoadResult result, List<LoadResource> files = null)
|
||||
{
|
||||
_callback?.Invoke((int)result, files);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 文件总大小
|
||||
/// </summary>
|
||||
public long FileSize
|
||||
{
|
||||
get
|
||||
{
|
||||
return _totalFileSize;
|
||||
}
|
||||
}
|
||||
|
||||
public long DownLoadSize
|
||||
{
|
||||
get => _downLoadedSize;
|
||||
set => _downLoadedSize = value;
|
||||
}
|
||||
|
||||
public long CurrentLoadSize()
|
||||
{
|
||||
return _downLoadedSize + _downloader.CurrentSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 返回下载速度
|
||||
/// </summary>
|
||||
public long Speed
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_downloader == null)
|
||||
return 0;
|
||||
|
||||
if (Time.time - _last_record_time < 0.5)
|
||||
{
|
||||
return _speed;
|
||||
}
|
||||
|
||||
float progress = _downloader.Progress;
|
||||
if (progress == _last_record_process)
|
||||
{
|
||||
return _speed;
|
||||
}
|
||||
|
||||
_speed = (long)((progress - _last_record_process) * _downloader.TotalSize / (Time.time - _last_record_time));
|
||||
_last_record_process = progress;
|
||||
_last_record_time = Time.time;
|
||||
return _speed;
|
||||
}
|
||||
}
|
||||
|
||||
public static IDownload GetDownloader(string url, string path, long totalLength, string md5, DownloadImpl imp)
|
||||
{
|
||||
DownloadHandlerFileRange loader = new DownloadHandlerFileRange(url, path, totalLength, md5);
|
||||
loader.SetImp(imp);
|
||||
return loader;
|
||||
}
|
||||
|
||||
public bool IsLoading()
|
||||
{
|
||||
if (_downloader == null)
|
||||
return false;
|
||||
return _downloader.Status == BackgroundDownloadStatus.Downloading;
|
||||
}
|
||||
|
||||
public BackgroundDownloadStatus Statue()
|
||||
{
|
||||
if (_downloader == null)
|
||||
return BackgroundDownloadStatus.NotBegin;
|
||||
return _downloader.Status;
|
||||
}
|
||||
|
||||
public bool IsNetWorkChanged()
|
||||
{
|
||||
if (_downloader == null)
|
||||
return false;
|
||||
return _downloader.Status == BackgroundDownloadStatus.NetworkError;
|
||||
}
|
||||
|
||||
public void StopDownLoad()
|
||||
{
|
||||
if (_downloader != null)
|
||||
{
|
||||
_downloader.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void Release()
|
||||
{
|
||||
_files = null;
|
||||
_path = "";
|
||||
_callback = null;
|
||||
_totalFileSize = 0;
|
||||
StopDownLoad();
|
||||
}
|
||||
}
|
||||
|
||||
public interface IDownload : IEnumerator
|
||||
{
|
||||
float Progress { get; }
|
||||
long TotalSize { get; }
|
||||
long CurrentSize { get; }
|
||||
BackgroundDownloadStatus Status { get; }
|
||||
|
||||
void Dispose();
|
||||
void StartDownload();
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a6103e1339c9a164ba4dc41f33be1cf3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
26
Assets/TEngine/Runtime/HotUpdate/Runtime/LoadData.cs
Normal file
26
Assets/TEngine/Runtime/HotUpdate/Runtime/LoadData.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TEngine
|
||||
{
|
||||
public enum GameStatus
|
||||
{
|
||||
First = 0,
|
||||
AssetLoad = 1
|
||||
}
|
||||
|
||||
public struct LoadResource
|
||||
{
|
||||
public string Url;//资源名称
|
||||
public string Md5;//资源的md5码
|
||||
public long Size; //资源大小(字节为单位)
|
||||
public string RemoteUrl;//服务器地址
|
||||
}
|
||||
|
||||
public class LoadData
|
||||
{
|
||||
}
|
||||
}
|
11
Assets/TEngine/Runtime/HotUpdate/Runtime/LoadData.cs.meta
Normal file
11
Assets/TEngine/Runtime/HotUpdate/Runtime/LoadData.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c685f02226943e946853424f953dcfee
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
98
Assets/TEngine/Runtime/HotUpdate/Runtime/LoadMgr.cs
Normal file
98
Assets/TEngine/Runtime/HotUpdate/Runtime/LoadMgr.cs
Normal file
@@ -0,0 +1,98 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace TEngine
|
||||
{
|
||||
public class LoadUpdateLogic
|
||||
{
|
||||
private static LoadUpdateLogic _instance;
|
||||
|
||||
public Action<int> Download_Complete_Action = null;
|
||||
public Action<long> Down_Progress_Action = null;
|
||||
public Action<bool, GameStatus> _Unpacked_Complete_Action = null;
|
||||
public Action<float, GameStatus> _Unpacked_Progress_Action = null;
|
||||
|
||||
public static LoadUpdateLogic Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
_instance = new LoadUpdateLogic();
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class LoadMgr : TSingleton<LoadMgr>
|
||||
{
|
||||
/// <summary>
|
||||
/// 资源版本号
|
||||
/// </summary>
|
||||
public string LatestResId { get; set; }
|
||||
|
||||
private Action _startGameEvent;
|
||||
private int _curTryCount;
|
||||
private const int MaxTryCount = 3;
|
||||
private bool _connectBack;
|
||||
private bool _needUpdate = false;
|
||||
|
||||
public LoadMgr()
|
||||
{
|
||||
_curTryCount = 0;
|
||||
_connectBack = false;
|
||||
_startGameEvent = null;
|
||||
}
|
||||
|
||||
public void StartLoadInit(Action onUpdateComplete)
|
||||
{
|
||||
#if RELEASE_BUILD || _DEVELOPMENT_BUILD_
|
||||
StartLoad(() => { FinishCallBack(onUpdateComplete); });
|
||||
#else
|
||||
onUpdateComplete();
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开启热更新逻辑
|
||||
/// </summary>
|
||||
/// <param name="action"></param>
|
||||
public void StartLoad(Action action)
|
||||
{
|
||||
_startGameEvent = action;
|
||||
_connectBack = false;
|
||||
_curTryCount = 0;
|
||||
RequestVersion();
|
||||
}
|
||||
|
||||
private void FinishCallBack(Action callBack)
|
||||
{
|
||||
GameConfig.Instance.WriteVersion(LatestResId);
|
||||
if (_needUpdate)
|
||||
{
|
||||
callBack();
|
||||
}
|
||||
else
|
||||
{
|
||||
callBack();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 请求热更数据
|
||||
/// </summary>
|
||||
private void RequestVersion()
|
||||
{
|
||||
if (_connectBack)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_curTryCount++;
|
||||
|
||||
if (_curTryCount > MaxTryCount)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Assets/TEngine/Runtime/HotUpdate/Runtime/LoadMgr.cs.meta
Normal file
11
Assets/TEngine/Runtime/HotUpdate/Runtime/LoadMgr.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 56d713df43471c642a913a349900d028
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
67
Assets/TEngine/Runtime/HotUpdate/Runtime/LoaderUtilities.cs
Normal file
67
Assets/TEngine/Runtime/HotUpdate/Runtime/LoaderUtilities.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace TEngine
|
||||
{
|
||||
public class LoaderUtilities
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// 删除文件
|
||||
/// </summary>
|
||||
/// <param name="filePath">文件路径</param>
|
||||
public static void DeleteFile(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(filePath))
|
||||
{
|
||||
File.Delete(filePath);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
TLogger.LogError(e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取文件的md5码
|
||||
/// </summary>
|
||||
/// <param name="fileName"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetMd5Hash(string fileName)
|
||||
{
|
||||
if (!File.Exists(fileName))
|
||||
{
|
||||
TLogger.LogWarning($"not exit file,path:{fileName}");
|
||||
return string.Empty;
|
||||
}
|
||||
try
|
||||
{
|
||||
using (FileStream file = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
{
|
||||
MD5 md5 = new MD5CryptoServiceProvider();
|
||||
byte[] retVal = md5.ComputeHash(file);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < retVal.Length; i++)
|
||||
{
|
||||
sb.Append(retVal[i].ToString("x2"));
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
TLogger.LogError("GetMD5Hash() fail,error:" + ex.Message);
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 186c876c2ef7f2f4db981fd403e22ce7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user