zoukankan      html  css  js  c++  java
  • [Flutter] 大文件上传之随传随处理(避免占用大量内存)

    今天碰到一个上传较大的视频文件到S3引发闪退的问题。经查此问题产生的原因是内存溢出,连个闪退日志都没有。

    这个上传使用的是第三方的插件,我是用 uploadFileStream 来上传文件的,查看其实现代码,它使用的是http插件的 http.StreamedRequest, 它会把文件分块读出来,添加分块签名,再使用 request.sink.add(xxx) 加入缓冲区, 最后调用 request.send() 来完成发送。

    这样问题就来了,它会把整个文件外加签名信息都放到缓冲区,意味着文件越大,也就占用更多的内存,最终导致崩溃的发生。

    由于需要对文件进行签名处理,不能直接使用 dio 插件文件上传方式(说不定dio也会有同样的问题,还没来得及细品)。http 插件也没有提供边读边处理边发送的方法,问题限入卡顿状态,在网上搜索半天也没有找到一个解决方案,最后想想,能不能直接用最基础的 HttpClient 来解决呢?

    因为平常主要用dio和http这两个插件,没有用过HttpClient,没有认真研究过它。这个时候想起来它,就马上细品起来,最终真的找到的解决方案。还真是越低级的封装,关键时候越能解决问题。

    下面给出使用 HttpClient 解决上面问题的关键代码:

        // 初始化一个Http客户端,并加入自定义Header
        var req = await HttpClient().putUrl(uri);
        headers.forEach((key, value) {
          req.headers.add(key, value);
        });
    
        // 读文件
        var s = await file.open();
        var x = 0;
        var size = file.lengthSync();
        var chunkSize = 65536;
        while (x < size) {
              var _len = size - x >= chunkSize  ? chunkSize : size - x;
              val = s.readSync(_len).toList();
              x = x + _len;
              // 处理数据块
              val = proc(val);
              // 加入http发送缓冲区
              req.add(val);
              // 立即发送并清空缓冲区
              await req.flush();
        }
        await s.close();
        
        // 文件发送完成
        await req.close();
        // 获取返回数据
        final response = await req.done;
        // 其它处理逻辑
        print("response statusCode: ${resp.statusCode}");

    经测试,用上面方法上传大文件,内存占用平稳,最后真机测试,也没有再闪退。

  • 相关阅读:
    jquery ready()的几种实现方法小结
    jQuery之$(document).ready()使用介绍
    jquery的$(document).ready()和onload的加载顺序
    php var_export与var_dump 输出的不同
    PHP获取和操作配置文件php.ini的几个函数
    PHP 网站保存快捷方式的实现代码
    php 图形验证码的3种方法
    面向对象基础01
    提高记忆力
    Python数据分析环境和工具
  • 原文地址:https://www.cnblogs.com/yangyxd/p/13094925.html
Copyright © 2011-2022 走看看