美文网首页
flutter分段下载Dio

flutter分段下载Dio

作者: FlowYourHeart | 来源:发表于2019-11-08 15:43 被阅读0次

    分块下载的最终速度受设备所在网络带宽、源出口速度、每个块大小、以及分块的数量等诸多因素影响,实际过程中很难保证速度最优。在实际开发中,可以先测试对比后再决定是否使用

    此处使用Dio的download方法

    import 'dart:io';
    import 'package:dio/dio.dart';
    
    class DioDownDataClass
    {
    /* *
     * Des: 分段下载
     * url:数据、资源的网络地址
     * savePath:下载下来的数据保存的位置
     * onReceivedProgress: 下载进度回调函数
     * */
    Future downloadWithChunks(url, savePath, {ProgressCallback onReceivedProgress})
       async {
         //第一次下载数据的长度 byte
         const firstChunkSize = 102;
         //最多几次能全部下完
         const maxChunk = 3;
         //下载的数据总长度
         int total = 0;
         //
         var dio = Dio();
    
         var progress = <int>[];
         
         createCallback(no) {
           return (int received, _) {
             progress[no] = received;
             if (onReceivedProgress != null && total != 0) {
               onReceivedProgress(progress.reduce((a, b) => a+b), total);
             }
           };
         }
       
      ////start 代表当前块的起始位置,end代表结束位置
    //nomber 代表当前是第几块
      Future<Response> downloadChunk(url, start, end, nomber) {
        progress.add(0);
        --end;
        return dio.download(
          url,
          savePath + "temp$nomber",
          onReceiveProgress: createCallback(nomber),
          options: Options(
            //指定请求的内容长度区间
            headers: {"range": "byte=$start-$end"}, 
          )
        );
      }
    
      //合并文件
      Future mergeTempFiles(chunk) async {
        File f = File(savePath+"temp0");
        IOSink ioSink = f.openWrite(mode: FileMode.writeOnlyAppend);
        //合并临时文件
        for (int i = 1; i < chunk; i ++) {
          File _f = File(savePath + "temp$i") ;
          await ioSink.addStream(_f.openRead());
          await _f.delete();
        }
        await ioSink.close();
        await f.rename(savePath);
      }
    
    
      Response response = await downloadChunk(url, 0 ,firstChunkSize, 0);
      if (response.statusCode == 206) { //支持分片下载
        //总长度
         total = int.parse(response.headers.value(HttpHeaders.contentRangeHeader).split("/").last);
         int reserved = total - int.parse(response.headers.value(HttpHeaders.contentLengthHeader));
         int chunk = (reserved / firstChunkSize).ceil() + 1;//分成多少段
         if ( chunk > 1) {
           int chunkSize = firstChunkSize;
           if (chunk > maxChunk + 1) {
             //如果按每次firtstChunkSize需要下载的次数chunk大于自定义最大次数maxChunk+1时
             chunk = maxChunk + 1;
             //不在以每次firstChunkSize下载而是按 次数maxChunk大小chunkSize进行下载
             chunkSize = (reserved / maxChunk).ceil();
           }
           var futures = <Future>[];
           for (var i=0 ;i < maxChunk; i++) {
            //每一次下载的起始位置
             int start = firstChunkSize + i * chunkSize;
             //开始下载文件
             futures.add(downloadChunk(url, start, start+chunkSize, i+1));
           }
           //等待所有分块全部下载完成
           await Future.wait(futures);
    
         }
         //合并文件 chunk 是分成的块数 futures 元素个数
         await mergeTempFiles(chunk);
      }
    
    
    }
      
    
    }
    

    分块下载有一个比较使用的场景就是断点续传,可以将文件分为若干个块,然后维护一个下载状态文件用以记录每一个块的状态,这样即使在网络中断后,也可以恢复中断前的状态,具体实现可以自己尝试一下

    flutter中文网(11.4 实例:Http分块下载)

    相关文章

      网友评论

          本文标题:flutter分段下载Dio

          本文链接:https://www.haomeiwen.com/subject/wlfwbctx.html