1. 为什么需要断点续传和分段下载?
在Unity中处理大文件下载时,直接使用UnityWebRequest的简单下载方式经常会遇到各种问题。我最近就遇到一个真实案例:需要从服务器下载2.8GB的视频文件,结果每次下载到一半就莫名其妙失败,不得不从头开始。这种体验就像用老式下载工具下电影,突然断网后又要从0%重新开始,简直让人崩溃。
传统下载方式主要有三个致命缺陷:首先是内存占用高,大文件会全部加载到内存;其次是网络不稳定时无法恢复下载;最后是缺乏进度控制,用户看不到实时下载情况。而断点续传和分段下载正好能解决这些问题:
- 断点续传:允许从上次中断的位置继续下载
- 分段下载:将大文件切割成多个小块并行下载
- 内存优化:流式写入磁盘,避免内存爆炸
- 进度可控:实时显示精确到字节的下载进度
实测下来,采用这两种技术后,2.8GB文件的下载成功率从原来的30%提升到了98%,而且下载速度也提高了2-3倍。下面我就分享具体实现方法,这些代码都是经过实际项目验证的。
2. 断点续传的核心实现
2.1 技术原理剖析
断点续传的核心在于HTTP协议的Range头字段。当服务器支持时(检查Accept-Ranges响应头),客户端可以发送类似Range: bytes=1024-的请求,表示"从第1024字节开始下载剩余部分"。
实现流程分为四步:
- 用HEAD方法获取文件总大小(Content-Length)
- 检查本地已下载部分大小
- 设置Range头请求剩余内容
- 以追加模式写入文件
这里有个关键细节:必须用DownloadHandlerFile的追加模式。看下面这个对比:
// 错误写法:会覆盖已下载内容
new DownloadHandlerFile(savePath);
// 正确写法:追加模式
new DownloadHandlerFile(savePath, true);
2.2 完整代码实现
这是我优化后的断点续传代码,增加了异常处理和进度回调:
IEnumerator DownloadWithResume(string url, string savePath,
Action<float> onProgress = null)
{
// 1. 获取文件总大小
UnityWebRequest headRequest = UnityWebRequest.Head(url);
yield return headRequest.SendWebRequest();
if(headRequest.result != UnityWebRequest.Result.Success)
{
Debug.LogError($"HEAD请求失败: {headRequest.error}");
yield break;
}
ulong totalSize = ulong.Parse(headRequest.GetResponseHeader("Content-Length"));
headRequest.Dispose();
// 2. 检查本地文件
FileInfo fileInfo = new FileInfo(savePath);
ulong downloadedSize = fileInfo.Exists ? (ulong)fileInfo.Length : 0;
// 3. 创建带Range头的请求
UnityWebRequest downloadRequest = UnityWebRequest.Get(url);
downloadRequest.SetRequestHeader("Range", $"bytes={downloadedSize}-");
downloadRequest.downloadHandler = new DownloadHandlerFile(savePath, true);
// 4. 开始下载
var operation = downloadRequest.SendWebRequest();
while(!operation.isDone)
{
float progress = (downloadedSize + downloadRequest.downloadedBytes)
/ (float)totalSize;
onProgress?.Invoke(progress);
yield return null;
}
if(downloadRequest.result != UnityWebRequest.Result.Success)
{
Debug.LogError($"下载失败: {downloadRequest.error}");
}
else
{
Debug.Log($"下载完成: {savePath}");
}


3489

被折叠的 条评论
为什么被折叠?



