• Harmonyos Next——图片上传与下载


    图片上传至服务器

    描述

    从手机相册中选择一张图片,然后上传至服务器

    选取图片

    在从相册或者拍摄获取的图片之前,需要进行权限申请,其权限为媒体内容读写权限

    ‘ohos.permission.READ_MEDIA’ //允许应用读取用户外部存储中的媒体文件信息-用户授权
    s’ohos.permission.WRITE_MEDIA’ //允许应用读写用户外部存储中的媒体文件信息-用户授权

    从相册选择图片

    通过picker.PhotoViewPicker()选择相册内容,在选择之前可以设置选择数量、资源类型等。
    例如选取其中一张图片,返回的URI格式如下:

    file://media/Photo/2/IMG_1713776063_001/screenshot_20240422_165243.jpg

    但此格式并不能直接上传至服务器,需要对其进行拷贝,格式转换等操作,将在下节进行阐述。

      private async openGallery(onSuccess: (uri: string)=> void, onFailed: (error: string)=>void) {
        try {
          let PhotoSelectOptions = new picker.PhotoSelectOptions()
          PhotoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE
          PhotoSelectOptions.maxSelectNumber = 1
          let photoPicker = new picker.PhotoViewPicker()
          photoPicker.select(PhotoSelectOptions).then((PhotoSelectResult: picker.PhotoSelectResult) => {
            //file://media/Photo/2/IMG_1713776063_001/screenshot_20240422_165243.jpg
            if (PhotoSelectResult.photoUris.length > 0) {
              onSuccess(PhotoSelectResult.photoUris[0])
            }
          }).catch((err: BusinessError) => {
            LoggerJoy.error('PhotoViewPicker.select failed with err: ' + JSON.stringify(err))
            onFailed(err.message)
          })
        } catch (error) {
          let err: BusinessError = error as BusinessError
          LoggerJoy.error('PhotoViewPicker failed with err: ' + JSON.stringify(err))
          onFailed(err.message)
        }
      }
    

    通过拍摄获取图片

    通过cameraPicker.pick打开相机页面,如果完成拍照并点击确认,则会返回如上节一样格式的URI

      private async openCamera(onSuccess: (uri: string)=> void, onFailed: (error: string)=>void){
        try {
          let pickerProfile: cameraPicker.PickerProfile = {
            cameraPosition: camera.CameraPosition.CAMERA_POSITION_BACK
          }
          let pickerResult: cameraPicker.PickerResult = await cameraPicker.pick(
            getContext(this),
            [cameraPicker.PickerMediaType.PHOTO, cameraPicker.PickerMediaType.VIDEO],
            pickerProfile
          )
          if (pickerResult) {
            onSuccess( pickerResult.resultUri)
          }
        } catch (error) {
          let err = error as BusinessError
          LoggerJoy.error(`the pick call failed. error code: ${err.code}`)
          onFailed(err.message)
        }
      }
    

    将获取的图片上传至服务器

    由于上述获取的文件为file开头,外部并不能直接进行访问,可以将其拷贝到APP目录下的沙箱文件中。由于本Demo采用的是系统提供的request.uploadFile,其路径前缀指定为internal://cache/,所有还需在拷贝之后的新路径前加上此前缀,此前缀对应的是临时目录cacheDir

    拷贝文件

    拷贝之后的文件存放于应用目录下的沙箱文件中

      private async copyFileToCache(path: string, context: Context): Promise<string>{
        try {
          let file = await fs.open(path, fs.OpenMode.READ_WRITE)
          if (file){
            let dir =  context.cacheDir + '/avatar'
            if (!fs.accessSync(dir)) {
              fs.mkdirSync(dir)
            }
            let newpath = context.cacheDir + `/avatar/hohem${new Date().getTime()}.jpg`
            LoggerJoy.info(`newpath:${newpath}`)
            await fs.copyFile(file.fd, newpath)
            return newpath
          }
          return ''
        } catch (err){
          LoggerJoy.info("applog:open file failed with error message: " + err.message + ", error code: " + err.code)
          return ''
        }
      }
    

    上传图片

    在使用request前需要导入对应包

    import { BusinessError, request } from ‘@kit.BasicServicesKit’

    拷贝之后的路径格式如下

    /data/storage/el2/base/haps/entry/cache/avatar/hohem1713924905931.jpg

    然后在其前面添加指定前缀internal://cache/,由于此前缀对应的便是cacheDir目录,所以将拷贝之后的路径前面一部分进行省略,最终得到的路径如下

    internal://cache/avatar/hohem1713924905931.jpg

    若未对路径进行转换,会出现401-the parameters check fails this is fail path异常错误。

    在进行上传时,需根据自己云服务器所配置的接受数据格式进行变化request.UploadConfig,例如是PUT还是POST,是否还需其他头参数,例如id、token等

      private async uploadFileToCloud(context: Context, uploadUrl: string, path: string, avatar: string, onSuccess: (avatar: string)=> void, onFailed: (error: string) => void){
        let newPath = await this.copyFileToCache(path, context)//---/data/storage/el2/base/haps/entry/cache/avatar/hohem1713924905931.jpg
        newPath = `internal://cache/${newPath.split("cache/")[1]}` //internal://cache/avatar/hohem1713924905931.jpg
        LoggerJoy.info(`newpath:${newPath}`)
        let file: Array<request.File> = [
          {
            name: 'avatarName',
            filename: 'avatarFilename',
            uri: newPath,
            type: 'image'
          }
        ]
    
        let config: request.UploadConfig = {
          url: uploadUrl,
          method: 'PUT',
          files: file,
          header: {
            'Content-Type': 'application/octet-stream'
          },
          data: []
        }
    
        try {
          request.uploadFile(
            context,
            config
          ).then((result)=>{
            onSuccess(avatar)
          }).catch((err: BusinessError)=>{
            onFailed(err.message)
          })
        } catch (error) {
          //401-the parameters check fails   this is fail path
          onFailed((error as BusinessError).message)
        }
      }
    

    图片下载

    下载图片比上传图片简单的多,依旧使用系统提供的request.downloadFileAPI完成。
    例如存在https://xxxxxxx.com/system/202403/1773228028463067136.jpgURL图片资源,
    为了减少文件名称冗余和唯一性,我们可以只截取最后一部分做为下载之后的图片名称(1773228028463067136.jpg),然后同样保存到应用目录下的沙箱文件下。
    最后调用request.downloadFile即可完成对应下载功能

      private downloadImages(context: Context,url: string){
        let splits = url.split('/')
        let fileName = splits[splits.length - 1]
        let basePath = context.cacheDir + '/banner' //:/data/storage/el2/base/haps/entry/cache/banner/1773228028463067136.jpg
        this.checkBannerDirExist(basePath) //如果目录不存在,则直接创建目录
        let config: request.DownloadConfig = {
          url: url,
          filePath: `${basePath}/${fileName}`
        }
        try {
          request.downloadFile(context, config, (err: BusinessError, data: request.DownloadTask)=>{
            if (err) {
              //下载失败
              LoggerJoy.info(`write local banner failed:${url}`)
              return
            }
            LoggerJoy.info(`download banner successful:${url}`)
            //下载成功
          })
        } catch (error) {
          LoggerJoy.info(`write local banner failed:${(error as BusinessError).message}`)
        }
      }
    
  • 相关阅读:
    数据包络分析(DEA)——BCC模型
    Explain 关键字
    在4元有限域下基于EMS算法的LDPC译码FPGA实现与仿真
    【C++面向对象侯捷】2.头文件与类的声明
    Postman —— postman实现参数化
    60、回溯-单词搜索
    10 读写锁ReentrantReadWriteLock
    Golang sync.Map大白话解析
    Win11怎么调亮度?Win11调屏幕亮度的四种方法
    java毕业设计球馆预约管理系统mybatis+源码+调试部署+系统+数据库+lw
  • 原文地址:https://blog.csdn.net/News53231323/article/details/139389123