HarmonyOS优化应用文件上传下载慢问题性能优化二

发布于:2025-05-23 ⋅ 阅读:(25) ⋅ 点赞:(0)

常见场景和解决方案
场景1:低带宽网络上传琐碎文件场景
在网络连接较差,低带宽的网络环境中,HTTP连接的建立耗时可能会大幅提升。这时候进行数据压缩可以加快页面加载速度,并减少HTTP请求数量和移动数据流量。
场景2:处理大量资源的场景
如应用商店、网盘应用等,这类应用通常拥有大体积的文件资源。当用户从暂停或者断网中重新恢复时,如果从头开始上传下载则会额外耗费大量的时间。此时可以采用断点续传方法进行上传下载。
(一)数据压缩
数据压缩是指在应用中对数据进行压缩,以减少存储空间和数据传输量、节省带宽,提高加载速度。数据压缩通常在网络传输和存储方面发挥着重要作用,特别是在处理大量数据或需要频繁传输数据的场景下。
在应用开发中,常见的数据压缩技术分类如下:
有损压缩:仅限图片视频音频等文件适用。通过减少图片视频文件的分辨率,降低音频的音质等手段,以减少文件的大小,来实现减少加载时间和带宽消耗。
无损压缩:对一些零碎文件可以使用 zlib(Zip模块)来进行打包压缩,减少上传请求次数;对一些大文件可以利用缓存技术,服务器将曾经上传过的大文件MD5码缓存起来,本地在上传前预生成MD5码并传输到服务器进行比对,如果相同则说明服务器存在该文件,可以跳过该文件上传,从而省略重复传输时间。
以批量上传照片(分辨率为480*640,24位,平均大小50~120KB)为例,在设备上测试的结果如下表所示:
 

HarmonyOS优化应用文件上传下载慢问题性能优化二-鸿蒙开发者社区


图2 上传数量和耗时对比图表
 

HarmonyOS优化应用文件上传下载慢问题性能优化二-鸿蒙开发者社区


由于上传耗时受到网络状态影响,偏差较大,结果取的几次测量结果的最小值。但是仍然可以从数据中看出,优化前的耗时基本为线性增长,压缩优化后的耗时在上传文件数量较低时并不明显,还会因为多余的压缩处理影响耗时。不过随着上传的照片数量增多,优化后的耗时和优化之前的耗时差距越来越明显,优化效果越好。
数据压缩的相关示例代码如下:
导入相关模块:

import { common } from '@kit.AbilityKit';
import { fileIo } from '@kit.CoreFileKit'
import { zlib } from '@kit.BasicServicesKit';

    创建压缩上传相关类:

    class ZipUpload {
      // 创建任务前存放的uri
      private waitList: Array<string> = [];
      // 需要上传的文件uri
      private fileUris: Array<string> = [];
      ...
    }
    
    

      建立用于接收图库图片的临时文件夹,并将整个临时文件夹打包添加到待上传list内:

      // 文件压缩处理
      async zipUploadFiles(fileUris: Array<string>): Promise<void> {
        this.context = getContext(this) as common.UIAbilityContext;
        let cacheDir = this.context.cacheDir;
        let tempDir = fileIo.mkdtempSync(`${cacheDir}/XXXXXX`);
        // 将图库图片获取的uri放入fileUris中,遍历复制到临时文件夹
        for (let i = 0; i < fileUris.length; i++) {
          let fileName = fileUris[i].split('/').pop();
          let resourceFile: fileIo.File = fileIo.openSync(fileUris[i], fileIo.OpenMode.READ_ONLY);
          fileIo.copyFileSync(resourceFile.fd, `${tempDir}/${fileName}`, 0);
          fileIo.closeSync(resourceFile);
        }
        // 文件压缩,将之前生成的临时文件夹内打包到test.zip内
        let options: zlib.Options = {
          level: zlib.CompressLevel.COMPRESS_LEVEL_DEFAULT_COMPRESSION,
          memLevel: zlib.MemLevel.MEM_LEVEL_DEFAULT,
          strategy: zlib.CompressStrategy.COMPRESS_STRATEGY_DEFAULT_STRATEGY
        };
        let data = await zlib.compressFile(tempDir, `${cacheDir}/test.zip`, options);
        // 删除临时文件夹
        fileIo.rmdirSync(tempDir);
        // 将生成的zip包放到传输队列
        this.waitList.push(`${cacheDir}/test.zip`);
      }
      
      

        (二)断点续传
        断点续传功能的实现,不管是应用端还是服务器端都需要用到合理的技术来互相协同。在实际开发中,开发者无需亲自实现断点续传功能,只需对SDK进行合理配置。
        在应用端需要用到的技术和API:
        fileIo(文件管理):用于处理文件上传操作,提供了读取文件内容,文件分片和组合的功能。
        hash(文件哈希处理):用于实现文件MD5的计算,将计算的MD5值预先传到服务器端进行预处理,实现文件秒传,同时确保传输的准确性和可靠性。
        request(上传下载):用于实现文件上传操作,并支持在上传过程中的断点续传功能。
        在服务器端需要用到的技术:
        协议需要支持Range:用于在服务器端支持范围请求,方便处理文件上传下载断点续传功能。
        文件校验相关逻辑:需要实现校验文件是否有错,确保在传输中断后能够准确恢复并继续传输。
        通过结合应用端和服务器端的相关技术,可以共同实现高效且可靠的文件断点续传功能,提供更好的用户体验并确保数据传输的稳定性。
        本文基于上传和下载中的后台上传场景,给出了部分断点续传的示例代码,具体可以参考该工程。
        (三)文件上传
        对于大文件断点续传上传,本文采用request(上传下载)模块中的request.agent任务托管接口,可以自动实现暂停继续重试等操作,无需手动将文件分片和记录上传分片信息。流程图如下图所示:
        图3 断点续传上传流程图
         

        HarmonyOS优化应用文件上传下载慢问题性能优化二-鸿蒙开发者社区


        导入相关模块:

        import { common } from '@kit.AbilityKit';
        import { request } from '@kit.BasicServicesKit';
        
        

          创建相关上传类:

           class Upload {
            // 后台任务
            private backgroundTask: request.agent.Task | undefined = undefined;
            // 创建任务前存放的uri
            private waitList: Array<string> = [];
            ...
          }
          
          

            配置Config,创建后台上传任务:

            private config: request.agent.Config = {
              action: request.agent.Action.UPLOAD,
              headers: HEADER,
              url: '',
              mode: request.agent.Mode.BACKGROUND,
              method: 'POST',
              title: 'upload',
              network: request.agent.Network.ANY,
              data: [],
              token: 'UPLOAD_TOKEN'
            }
            ...
            // 转换uri
            private async getFilesAndData(cacheDir: string, fileUris: Array<string>): Promise<Array<request.agent.FormItem>> {
            ...
            }
            // 创建文件上传后台任务
            async createBackgroundTask(fileUris: Array<string>) {
              if (this.context === undefined) {
                return;
              }
              // 获取上传url
              this.config.url = await urlUtils.getUrl(this.context);
              this.config.data = await this.getFilesAndData(this.context.cacheDir, fileUris);
              this.config.mode = request.agent.Mode.BACKGROUND;
              try {
                this.backgroundTask = await request.agent.create(this.context, this.config);
                await this.backgroundTask.start();
                let state = AppStorage.get<number>('backTaskState');
                if (state === BackgroundTaskState.PAUSE) {
                  await this.backgroundTask.pause();
                }
                logger.info(TAG, `createBackgroundTask success`);
              } catch (err) {
                logger.error(TAG, `task  err, err  = ${JSON.stringify(err)}`);
              }
            }
            
            

              任务开始:

              await this.backgroundTask.start();
              
              

                任务暂停:

                async pause() {
                  ...
                  if (this.backgroundTask === undefined) {
                    return;
                  }
                  await this.backgroundTask.pause();
                }
                
                

                  任务继续

                  async resume() {
                    ...
                    if (this.backgroundTask === undefined) {
                      return;
                    }
                    await this.backgroundTask.resume();
                  }
                  
                  

                    本文主要引用参考HarmonyOS官方文档


                    网站公告

                    今日签到

                    点亮在社区的每一天
                    去签到