参考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%') } }
参考demo: