Flutter 上传带有进度条的大文件。 App 和 Web 都支持

Posted

技术标签:

【中文标题】Flutter 上传带有进度条的大文件。 App 和 Web 都支持【英文标题】:Flutter upload large file with progress bar. App and Web both support 【发布时间】:2021-06-23 04:49:49 【问题描述】:

我遇到上传大文件的问题。当从应用程序上传文件工作正常但网络挂起时,为 Web 和应用程序(本机)编译的颤振应用程序。如何将大文件作为流请求发送。

我是 Flutter 的新手,正在开发当前现有的应用程序,该应用程序具有上传大型教程视频文件和 PDF 文件的功能。要求是在上传文件的过程中显示进度条,目前应用程序我使用了dio,但它在网页版中挂起,而不是文件不上传操作失败。

文件大小约为 400MB 到 700MB

目前使用以下包

dependencies:
  http: ^0.12.2
  dio: ^3.0.10

你能帮我解决这个问题吗?

我正在尝试使用以下代码来实现,但有些代码无法正常工作。 https://github.com/salk52/Flutter-File-Upload-Download

抛出“内存缓冲区分配失败”之类的错误,由于其他包干扰,我无法更新dio或http的版本。不知何故,我必须使用httpclientdio 来实现它。我无法更新包的版本,因为它弄乱了其他包的依赖关系。

示例参考。代码如下: 文件大小约为 500 MB 到 700MB

对于参考。以下代码在代码中使用。

Dio封装示例:

#Dio example start

  Future<NormalResponse> addSubjectMaterial(
      GetSubjectMaterial objSubMat,
      bool isDelete,
      PlatformFile objfile,
      Function sendProgress,
      Function receiveProgress,
      dio.CancelToken cancelToken) async 
    NormalResponse objRes = NormalResponse();
    try 
      print(objSubMat.objMaterial.subjectId);
      dio.FormData formData = dio.FormData();
      formData.fields.add(MapEntry("ObjSubMat", json.encode(objSubMat)));
      formData.fields.add(MapEntry("IsDelete", isDelete.toString()));
      formData.fields
          .add(MapEntry("ClassesId", AppConstants.classesId().toString()));
      if (objfile != null) 
        formData.files.add(
            MapEntry("objfile", await getMultipartFile(objfile, "objfile")));
      
      var resp = await dio.Dio().post(
        AppConstants.addUpdateSubjectMaterial,
        data: formData,
        options: requestConfig,
        cancelToken: cancelToken,
        onSendProgress: sendProgress,
        onReceiveProgress: receiveProgress,
      );

      // String respStr = resp.toString();
      // objRes = NormalResponse.fromJson(json.decode(respStr));
      objRes = NormalResponse.fromJson(resp.data);
     catch (err) 
      objRes.err = err.toString();
      objRes.isSuccess = false;
      objRes.newId = -1;
      sendProgress = null;
      receiveProgress = null;
    
    return objRes;
  

#Dio example end

#httpclient example code is there any solution with progress bar in this sample code.

   Future<NormalResponse> addUpdateSubjectMaterialHttp(
       GetSubjectMaterial objSubMat,
       bool isDelete,
       PlatformFile objfile,
       Function sendProgress,
       Function receiveProgress,
       dio.CancelToken cancelToken) async 
     NormalResponse objRes = NormalResponse();
     try 
       var req = http.MultipartRequest(
         "POST",
         Uri.parse(AppConstants.addUpdateSubjectMaterial),
       );
       req.headers.addAll(
         'Content-type': 'application/json',
         'Accept': 'application/json',
       );
       req.fields['ObjSubMat'] = json.encode(objSubMat);
       req.fields['IsDelete'] = isDelete.toString();
       req.fields['ClassesId'] = AppConstants.classesId().toString();

       if (objfile != null) 
         req.files.add(http.MultipartFile(
             "objFile", objfile.readStream, objfile.size,
             filename: objfile.name));
       

       var resp = await req.send();
       String result = await resp.stream.bytesToString();
       objRes = NormalResponse.fromJson(json.decode(result));
       print(objRes.isSuccess);
       print(objRes.err);
       print("Here done");
      catch (err) 
       print(err);
       throw err;
     
     return objRes;
   
   
#httpclient


Http package example:

#example start

  Future<NormalResponse> addSubjectMaterial(
      GetSubjectMaterial objSubMat,
      bool isDelete,
      PlatformFile objfile,
      Function sendProgress,
      Function receiveProgress,
      dio.CancelToken cancelToken) async 
    NormalResponse objRes = NormalResponse();
    try 
      print(objSubMat.objMaterial.subjectId);
      dio.FormData formData = dio.FormData();
      formData.fields.add(MapEntry("ObjSubMat", json.encode(objSubMat)));
      formData.fields.add(MapEntry("IsDelete", isDelete.toString()));
      formData.fields
          .add(MapEntry("ClassesId", AppConstants.classesId().toString()));
      if (objfile != null) 
        formData.files.add(
            MapEntry("objfile", await getMultipartFile(objfile, "objfile")));
      
      var resp = await dio.Dio().post(
        AppConstants.addUpdateSubjectMaterial,
        data: formData,
        options: requestConfig,
        cancelToken: cancelToken,
        onSendProgress: sendProgress,
        onReceiveProgress: receiveProgress,
      );

      // String respStr = resp.toString();
      // objRes = NormalResponse.fromJson(json.decode(respStr));
      objRes = NormalResponse.fromJson(resp.data);
     catch (err) 
      objRes.err = err.toString();
      objRes.isSuccess = false;
      objRes.newId = -1;
      sendProgress = null;
      receiveProgress = null;
    
    return objRes;
  

#example end

【问题讨论】:

【参考方案1】:

您必须使用 Future、await 和 async,它们在后台线程中继续流的任务,同时您的应用程序的 UI 工作顺利。

【讨论】:

能否提供一些示例代码。 好的@DharmeshChauhan 我正在编辑我的答案,但请回复您使用什么来存储数据,firebase 或其他任何东西或 mysql 您好 Manav,感谢您的回复。我正在使用 API 调用它。在 App 版本中,它也可以与简单的 html 页面一起正常工作。 @DharmeshChauhan 当我通读您的代码时,您似乎已经正确地实现了所有的东西。我有一个建议为 web 构建一个版本,然后尝试,因为您正在尝试调试模式。谢谢。

以上是关于Flutter 上传带有进度条的大文件。 App 和 Web 都支持的主要内容,如果未能解决你的问题,请参考以下文章

带有进度条的 jQuery ajax 上传 - 没有 flash

Alamofire 上传带有进度的大文件并在应用重启时显示进度

带进度条的文件上传?

springboot带有进度条的上传

使用 HTML5 和 Javascript 录制/上传带有进度条的固定长度视频

使用 Util.copyStream 的带有进度条的 FTP - JAVA