[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}");

 

經測試,用上面方法上傳大文件,內存占用平穩,最后真機測試,也沒有再閃退。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM