鸿蒙开发中遇到的那点坑-文件下载

160 阅读1分钟

本文主要记录使用两种下载文件的方法踩到的坑(基于api 16)及对应的处理方式, 至于具体用法请自行参考官方文档

背景: 关于文件下载, 目前使用到的方法有以下两种:

  1. ohos.request ## downloadFile : 文件太小时有遇到问题
  2. rcp.createSession ## downloadToFile : 文件太大时有遇到问题

问题1: 使用reuest.downloadFile下载小文件(如几KB甚至更小的缩略图)时, 下载完成后并不会触发 下载完成(onComplete)的回调, 需要根据下载进度(progress)判断是否下载完成

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


let context = this.getUIContext().getHostContext() as common.UIAbilityContext;
try {
  request.downloadFile(context, { url: 'https://xxxx/xxxx.hap' }).then((data: request.DownloadTask) => {
  
    // 1. 当文件很小时, 下载完成后不会执行这个回调
    let downloadTask: request.DownloadTask = data;
    let completeCallback = () => {
      console.info('Download task completed.');
    };
    downloadTask.on('complete', completeCallback);

    // 2. 需要在下载进度的回调中判断是否下载完成、 并执行下载完成的逻辑
    let progressCallback = (receivedSize: number, totalSize: number) => {
        if ( receivedSize === totalSize ) {
          // .... 下载完成的逻辑
        }    
    };
    downloadTask.on('progress', progressCallback);
  }).catch((err: BusinessError) => {
    console.error(`Failed to request the download. Code: ${err.code}, message: ${err.message}`);
  })
} catch (err) {
  console.error(`Failed to request the download. err: ${JSON.stringify(err)}`);
}

问题2: 使用rcp.session进行切片下载时, 如果单个分片大小超过50MB, 能下载成功、但会写入文件失败, 需要严格确保切片不超过50MB

/**
 * 下载文件指定位置的文件切片
 *
 * @param index 第n个切片
 * @param start 当前切片第一个字节在文件中的位置下标
 * @param end   当前切片最后一个字节在文件中的位置下标
 * 
 * 当end-start > 50*1024*1024时, 即指定的分片大于50MB, 能下载成功但会写文件失败
 */
private downloadPart(index: number start: number, end: number ) {
    const sessionConfig: rcp.SessionConfiguration = ...
    const session = rcp.createSession(sessionConfig);
    const req = new rcp.Request(this.url, "GET", {
      'Range': `bytes=${start}-${end}`
    });
    // 分块内容
    session.fetch(req).then(( response: rcp.Response ) => {
        // 处理下载结果
        if ( response.statusCode === 206 && response.body ) {
          // 将数据保存到临时文件
          const path = `${this.context.tempDir}/downloaded_file_part_${index}.part`
          const file = fs.openSync(path, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE)

            /*******************************************************/
           // 超过50MB时会导致写入失败   {"code":1007900023,"data":"Failed writing received data to disk/application","extendInfo":xxx}
           // 解决方案: 现通过 downloadAssistant 对分块大小进行控制、计算
           fs.write(file.fd, response.body).then(( value: number ) => {
            //console.info(TAG + "成功 ===>>>> Downloaded and write success:", index, value);
            /*******************************************************/
          })
        }
        session.close()
    }).catch(( error: BusinessError ) => {
        // 异常处理...
    });
}