You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Dart通过Http Range头实现断点续传后视频文件损坏无法播放问题求助

断点续传代码错误分析与修复

核心问题点

  1. 文件打开模式错误
    你每次调用下载函数时都使用FileMode.write模式打开文件,该模式会直接截断原有文件,将已有内容全部清空。第二次续传时,前50MB的已下载内容直接被清空,你再从50MB偏移位置写入新数据,文件前半部分全为空值,自然无法正常播放。

  2. 文件句柄未正常关闭
    下载完成的onDone回调中没有关闭RandomAccessFile对象,内存中未刷入磁盘的缓存数据会丢失,也可能导致文件结构损坏。

  3. 缺少Range请求校验
    发送Range断点请求后,没有校验服务器是否返回206 Partial Content状态码,如果服务器不支持断点续传返回了200全量响应,你的偏移写入逻辑会直接出错。

  4. 异步逻辑存在隐患
    Stream回调嵌套执行同步IO操作,没有对异步流程做正确控制,可能出现写入顺序错乱的问题。

修复后的代码

downloadFile(String url, {int downloadFrom=0, int downloadUntil=99999999999 }) async {
  var httpClient = http.Client();
  try {
    var request = http.Request('GET', Uri.parse(url));
    request.headers.addAll({'Range': 'bytes=$downloadFrom-$downloadUntil'});
    var response = await httpClient.send(request);

    // 校验断点续传是否生效
    if (response.statusCode != 206) {
      throw Exception("服务器不支持断点续传");
    }

    // 下载从头开始就用write模式截断旧文件,续传用writeOnlyCreate保留已有内容不截断
    RandomAccessFile raf = await File(downloadPath).open(
      mode: downloadFrom == 0 ? FileMode.write : FileMode.writeOnlyCreate
    );
    int downloaded = downloadFrom;

    // 用await for处理流避免回调嵌套问题
    await for (var chunk in response.stream) {
      debugPrint('当前段下载进度: ${downloaded / (downloadFrom + response.contentLength!) * 100}');
      await raf.setPosition(downloaded);
      await raf.writeFrom(chunk);
      downloaded += chunk.length;
    }

    debugPrint('下载完成');
    await raf.close();
  } catch (e) {
    debugPrint('下载出错: $e');
    rethrow;
  } finally {
    httpClient.close();
  }
}

额外注意点

  • 第一次下载完成后一定要确保文件已经正常关闭,再执行续传操作
  • 如果需要计算全文件的下载进度,可以先发送一次HEAD请求获取文件总大小,再用已下载的字节数除以总大小计算

内容的提问来源于stack exchange,提问作者kurdish sage

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 03:57:02