HarmonyOS 需要一个web端保存图片或文件相关API demo?

因app中有h5页面有需要保存图片或文件到手机的需求,ohos.permission.WRITE\_IMAGEVIDEO权限申请有困难,能不能同提供一个demo?

阅读 555
1 个回答

参考demo:

//Constants.ets 
export const BASE64_IMAGE_STR = 'xxx'
//SaveImageUtil.ets
/**
 * 保存图片工具类
 */
import { BusinessError, request } from '@kit.BasicServicesKit'
import { common } from '@kit.AbilityKit'
import { buffer } from '@kit.ArkTS'
import { fileIo as fs, fileUri } from '@kit.CoreFileKit'
import { photoAccessHelper } from '@kit.MediaLibraryKit'
import FileUtil from './FileUtil'

class SaveImageUtil {
  private context = getContext(this) as common.UIAbilityContext
  async saveImageToApplication(image: string, dirPath: string, fileName: string): Promise<SaveImageResultVo> {
    return new Promise(async (resolve: Function, reject: Function) => {
      if (!fs.accessSync(dirPath)) {
        fs.mkdirSync(dirPath)
      }
      if (image.startsWith('http')) {
        // 如果是网络图片,则下载图片
        try {
          request
            .downloadFile(this.context, { url: image, filePath: `${dirPath}/${fileName}` })
            .then((downloadTask) => {
              console.debug(`image => 保存图片到应用沙盒`)
              downloadTask
                .on('complete', () => {
                  // 图片下载完成
                  let vo = new SaveImageResultVo
                  vo.errorCode = 0
                  resolve(vo)
                })
              downloadTask
                .on('fail', (err: number) => {
                  let vo = new SaveImageResultVo
                  vo.errorCode = err
                  resolve(vo)
                })
            })
            .catch((error: BusinessError) => {
              reject(error)
            })
        } catch (err) {
          reject(err)
        }
      } else {
        // base64图片
        let content = image
        if (image.startsWith('data:')) {
          // 如果是data:,则截取,后的数据
          content = image.split(',')[1]
        }
        try {
          const decodeBuff = buffer.from(content, 'base64').buffer
          FileUtil.writeBufferToFile(dirPath,fileName,decodeBuff)
          let vo = new SaveImageResultVo
          vo.errorCode = 0
          resolve(vo)
        } catch (err) {
          reject(err)
        }
      }
    })
  }

  /**
   * 保存图片到相册
   * @param path 图片路径
   * @param title 标题
   * @param extension 文件扩展名
   * @returns
   */
  async saveImageToAlbum(path: string, title?: string, extension?: string): Promise<boolean> {
    return new Promise(async (resolve: Function, reject: Function) => {
      try {
        let phAccessHelper = photoAccessHelper.getPhotoAccessHelper(this.context)
        let srcFileUri: Array<string> = [fileUri.getUriFromPath(path)]
        let photoCreationConfigs: Array<photoAccessHelper.PhotoCreationConfig> = [
          {
            title:'保存图片',
            fileNameExtension: extension ? extension : 'jpg',
            photoType: photoAccessHelper.PhotoType.IMAGE,
            subtype: photoAccessHelper.PhotoSubtype.DEFAULT
          }
        ]
        let desFileUris: Array<string> = await phAccessHelper.showAssetsCreationDialog(srcFileUri, photoCreationConfigs)
        if (desFileUris.length > 0) {
          for (let index = 0; index < desFileUris.length; index++) {
            FileUtil.copyFileContentTo(srcFileUri[index], desFileUris[index])
          }
          resolve(true)
        } else {
          resolve(false)
        }
      } catch (err) {
        reject(err)
      }
    })
  }
}
export class SaveImageResultVo {
  errorCode: number = 0
}
export default new SaveImageUtil()
//FileUtil.ets
import fs, { ReadOptions, WriteOptions } from '@ohos.file.fs'
import { util } from '@kit.ArkTS'
import { common } from '@kit.AbilityKit'

class FileUtil {
  private context = getContext(this) as common.UIAbilityContext
  /**
   * 将内容写入文件
   * @param dirPath 文件及路径
   * @param fileName 文件名称
   * @param content 内容
   */
  writeContentToFile(dirPath: string, fileName: string, content: string) {
    if (!fs.accessSync(dirPath)) {
      // 如果文件夹不存在,则先创建文件夹
      fs.mkdirSync(dirPath)
    }

    let file = fs.openSync(`${dirPath}/${fileName}`, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
    fs.writeSync(file.fd, content)
    fs.closeSync(file)
  }
  /**
   * 保存文件
   * @param dirPath
   * @param fileName
   * @param buf
   */
  writeBufferToFile(dirPath: string, fileName: string, buf: ArrayBuffer) {
    if (!fs.accessSync(dirPath)) {
      // 如果文件夹不存在,则先创建文件夹
      fs.mkdirSync(dirPath)
    }

    let file = fs.openSync(`${dirPath}/${fileName}`, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
    fs.writeSync(file.fd, buf)
    fs.closeSync(file)
  }
  /**
   * 读取文件内容
   * @param filePath 文件路径
   * @returns 文件内容
   */
  readContentFromFile(filePath: string): string {
    let result = ''
    if (fs.accessSync(filePath)) {
      let file = fs.openSync(filePath, fs.OpenMode.READ_ONLY)
      let bufSize = 4096
      let readSize = 0
      let buf = new ArrayBuffer(bufSize)
      let readOptions: ReadOptions = {
        offset: readSize,
        length: bufSize
      }
      let readLen = fs.readSync(file.fd, buf, readOptions)
      result = util.TextDecoder.create('utf-8').decodeWithStream(new Uint8Array(buf))
      while (readLen > 0) {
        readSize += readLen
        readOptions.offset = readSize
        readLen = fs.readSync(file.fd, buf, readOptions)
        result += util.TextDecoder.create('utf-8').decodeWithStream(new Uint8Array(buf))
      }
      fs.closeSync(file)
    }
    return result
  }

  /**
   * 复制文件内容到目标文件
   * @param srcFilePath 源文件路径
   * @param destFilePath 目标文件路径
   */
  copyFileContentTo(srcFilePath: string, destFilePath: string) {
    let srcFile = fs.openSync(srcFilePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)
    let destFile = fs.openSync(destFilePath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)

    // 读取源文件内容并写入至目的文件
    let bufSize = 4096;
    let readSize = 0;
    let buf = new ArrayBuffer(bufSize);
    let readOptions: ReadOptions = {
      offset: readSize,
      length: bufSize
    };
    let readLen = fs.readSync(srcFile.fd, buf, readOptions);
    while (readLen > 0) {
      readSize += readLen;
      let writeOptions: WriteOptions = {
        length: readLen
      };
      fs.writeSync(destFile.fd, buf, writeOptions);
      readOptions.offset = readSize;
      readLen = fs.readSync(srcFile.fd, buf, readOptions);
    }
    // 关闭文件
    fs.closeSync(srcFile);
    fs.closeSync(destFile);
  }

  /**
   * 删除文件
   * @param filePath 文件路径
   */
  deleteFile(filePath: string) {
    if (fs.accessSync(filePath)) {
      fs.rmdirSync(filePath)
    }
  }

  /**
   * 将Raw中的文件复制到应用沙盒中
   * @param rawFilePath Raw中文件路径
   * @param destDirPath 目标文件夹路径
   * @param fileName 文件名
   */
  copyRawFileToApplicationStorage(rawFilePath: string, destDirPath: string, fileName: string) {
    if (!fs.accessSync(destDirPath)) {
      // 如果文件夹不存在,则先创建文件夹
      fs.mkdirSync(destDirPath)
    }
    let srcFile = this.context.resourceManager.getRawFdSync(rawFilePath)
    let dest = fs.openSync(`${destDirPath}/${fileName}`, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE)
    let bufSize = 4096
    let buf = new ArrayBuffer(bufSize)
    let off = 0, len = 0, readLength = 0
    while (len = fs.readSync(srcFile.fd, buf, { offset: srcFile.offset + off, length: bufSize })) {
      readLength += len
      fs.writeSync(dest.fd, buf, { offset: off, length: len })
      off = off + len
      if ((srcFile.length - readLength) < bufSize) {
        bufSize = srcFile.length - readLength
      }
    }
    fs.close(dest.fd)
  }
}
export default new FileUtil()
//Index.ets
import { SaveImageResultVo, SaveImageUtil } from './SaveImageUtil'
import { common } from '@kit.AbilityKit';
import { BusinessError, request } from '@kit.BasicServicesKit';
import { BASE64_IMAGE_STR } from './Constants';
import { fileIo } from '@kit.CoreFileKit';

@Entry
@Component
struct Index {
  private context = getContext(this) as common.UIAbilityContext

  build() {
    Column() {
      Button('保存网络图片到应用沙盒')
        .width('100%')
        .height(40)
        .fontSize(16)
        .fontWeight(FontWeight.Bold)
        .fontColor(Color.White)
        .onClick(async () => {
          console.debug(`image => 保存网络图片到应用沙盒`)
          let dirPath = this.context.cacheDir
          let fileName = 'temp2.jpg'
          if (fileIo.accessSync(`${dirPath}/${fileName}`)) {
            fileIo.rmdirSync(`${dirPath}/${fileName}`)
          }

          try {
            let result: SaveImageResultVo = await SaveImageUtil.saveImageToApplication(`xxx`, dirPath, fileName)
            if (0 == result.errorCode) {
              // 图片保存成功
              console.debug(`image => 保存图片到应用沙盒成功`)
              SaveImageUtil
                .saveImageToAlbum(`${dirPath}/${fileName}`)
                .then((result) => {
                  if (result) {
                    console.debug(`image => 保存图片到相册成功`)
                  } else {
                    console.debug(`image => 用户拒绝授权`)
                  }
                })
                .catch((error: BusinessError) => {
                  console.error('image => 保存图片到相册异常:')
                })
            }
          } catch (err) {
            console.error(err, 'image => 保存图片到应用沙盒异常:')
          }
        })

      Button('保存BASE64图片到应用沙盒')
        .width('100%')
        .height(40)
        .fontSize(16)
        .fontWeight(FontWeight.Bold)
        .fontColor(Color.White)
        .margin({ top: 15 })
        .onClick(() => {
          console.debug(`image => 保存网络图片到应用沙盒`)
          let dirPath = this.context.cacheDir
          let fileName = 'temp2.jpg'
          if (fileIo.accessSync(`${dirPath}/${fileName}`)) {
            fileIo.rmdirSync(`${dirPath}/${fileName}`)
          }
          SaveImageUtil
            .saveImageToApplication(BASE64_IMAGE_STR, dirPath, fileName)
            .then((data) => {
              if (0 == data.errorCode) {
                console.debug(`image => 保存图片到应用沙盒成功`)
              } else {
                console.debug(`image => 保存图片到应用沙盒失败:${data.errorCode}`)
              }
            })
            .catch((error: BusinessError) => {
              console.error('image => 保存图片到应用沙盒异常:')
            })
        })
    }
    .padding(15)
    .height('100%')
    .width('100%')
  }
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进