HarmonyOS 鸿蒙Next中如何将图库中的图片复制到自己的应用沙箱?

HarmonyOS 鸿蒙Next中如何将图库中的图片复制到自己的应用沙箱? 使用photoAccessHelper.PhotoViewPicker,拉起图库,选择一张图片,然后用fs的cpoy方法将选择的图片复制到自己的沙箱路径,发现复制不了。

3 回复

你好,将图库的图片复制到自己应用沙箱,可以用@ohos.file.fs 模块的fs.copyFile或者fs.copyFileSync 方法进行复制。示例如下:

import { fileUri } from '@kit.CoreFileKit';
import fs from '[@ohos](/user/ohos).file.fs';
import { abilityAccessCtrl, common, PermissionRequestResult, Permissions } from '@kit.AbilityKit';
import { photoAccessHelper } from '@kit.MediaLibraryKit';

@Entry
@Component
struct Index {
  private srcUri: string = '';
  @State src: string = fileUri.getUriFromPath(this.srcUri);
  @State copySrc: string = '';

  aboutToAppear(): void {
    this.requestPermissions(["ohos.permission.READ_IMAGEVIDEO", "ohos.permission.WRITE_IMAGEVIDEO"]);
  }

  requestPermissions(permissions: Array<Permissions>): void {
    let atManager: abilityAccessCtrl.AtManager = abilityAccessCtrl.createAtManager();
    atManager.requestPermissionsFromUser(this.getUIContext().getHostContext() as common.UIAbilityContext, permissions)
      .then((data: PermissionRequestResult) => {
      })
      .catch((err: Error) => {
      })
  }

  copyFile(): void {
    console.info(`=-=:srcUri will copied: ${this.srcUri}`);
    try {
      let sourceFile: fs.File = fs.openSync(this.srcUri, fs.OpenMode.READ_WRITE);
      let context: common.UIAbilityContext = this.getUIContext().getHostContext() as common.UIAbilityContext;
      const base: string = context.filesDir;
      const resourcesDir: string = `${base}/resources`;
      const baseDir: string = `${resourcesDir}/base`;
      const mediaDir: string = `${baseDir}/media`;
      if (!fs.accessSync(mediaDir)) {
        fs.mkdirSync(mediaDir, true);
      }
      let destDir: string = `${mediaDir}/test.jpg`; //沙箱路径:/data/storage/el2/base/haps/entry/files/resources/base/media/test.jpg
      console.info(`=-=:destDir: ${destDir}`);
      if (fs.accessSync(destDir)) {
        console.info(`=-=:destDir: is exist`);
        fs.unlinkSync(destDir);
      }
      let destFile: fs.File = fs.openSync(destDir, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
      fs.copyFileSync(sourceFile.fd, destFile.fd);
      console.info(`=-=: copyFile success:target file;${destFile.path}`);
      this.copySrc = `file://${destDir}`;
      console.info(`=-=: this.copySrc:${this.copySrc}`);
      fs.closeSync(sourceFile);
    } catch (error) {
      console.error(`=-=: copyFile fail:${JSON.stringify(error)}`);
    }
  }

  private async selectImage(): Promise<void> {
    const picker: photoAccessHelper.PhotoViewPicker = new photoAccessHelper.PhotoViewPicker();
    try {
      const selectResult: photoAccessHelper.PhotoSelectResult = await picker.select({ maxSelectNumber: 1 });
      const uris: string[] = selectResult.photoUris;
      if (!uris || uris.length === 0) {
        console.warn('=-=:ImageManager: No image selected');
      }
      console.log(`=-=:the selectImage:${JSON.stringify(uris)}`);
      this.srcUri = uris[0]; //这里只获取一张图片
      this.src = fileUri.getUriFromPath(this.srcUri);
      console.log(`=-=:the load image path:${this.src}`);
    } catch (error) {
      console.error(`=-=:selectImage fail:${JSON.stringify(error)}`);
    }

  }

  build() {
    Column({ space: 20 }) {
      Column() {
        Text('SelectedImage:')
        Image(this.src)
          .height(50)
          .width(50)
          .onError((error: ImageError) => {
            console.error('=-=:load image err' + JSON.stringify(error));
          })
      }

      Column() {
        Text('CopiedImage:')
        Image(this.copySrc)
          .height(50)
          .width(50)
          .onError((error: ImageError) => {
            console.error('=-=:load CopiedImage  err' + JSON.stringify(error));
          })
      }

      Button('Select File')
        .onClick((event: ClickEvent) => {
          this.selectImage();
        })

      Button('Copy file')
        .onClick((event: ClickEvent) => {
          this.copyFile();
        })
    }
    .height('100%')
    .width('100%')
  }
}

cke_4043.png

更多关于HarmonyOS 鸿蒙Next中如何将图库中的图片复制到自己的应用沙箱?的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


在HarmonyOS Next中,使用photoAccessHelper模块获取图库图片的URI,然后通过fs模块的copyFile方法将图片复制到应用沙箱目录。需要申请ohos.permission.READ_IMAGEVIDEO权限。具体步骤:获取图片URI后,调用fs.copyFile(srcUri, destUri)完成复制。

在HarmonyOS Next中,将图库图片复制到应用沙箱的正确方式是使用photoAccessHelper模块获取图片的Uri,然后通过安全访问框架复制文件,而不是直接使用fs.copy。以下是关键步骤:

  1. 使用PhotoViewPicker选择图片

    import photoAccessHelper from '[@ohos](/user/ohos).file.photoAccessHelper';
    
    let photoPicker = new photoAccessHelper.PhotoViewPicker();
    photoPicker.select({
      maxSelectNumber: 1,
      MIMEType: ['image/*']
    }).then((photoSelectResult: photoAccessHelper.PhotoSelectResult) => {
      if (photoSelectResult.photoUris.length > 0) {
        let selectedUri = photoSelectResult.photoUris[0];
        // 获取Uri后复制到沙箱
        copyToSandbox(selectedUri);
      }
    }).catch((err: Error) => {
      console.error('选择图片失败:', err);
    });
    
  2. 通过安全访问框架复制文件

    import fs from '[@ohos](/user/ohos).file.fs';
    import { BusinessError } from '[@ohos](/user/ohos).base';
    
    async function copyToSandbox(uri: string) {
      let sandboxPath: string = getContext().filesDir + '/myImage.jpg'; // 沙箱目标路径
      
      try {
        // 1. 通过Uri打开源文件
        let srcFile = fs.openSync(uri, fs.OpenMode.READ_ONLY);
        
        // 2. 创建目标文件
        let destFile = fs.openSync(sandboxPath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
        
        // 3. 复制数据
        let bufferSize = 1024 * 1024; // 1MB缓冲区
        let buffer = new ArrayBuffer(bufferSize);
        let offset = 0;
        
        while (true) {
          let readResult = fs.readSync(srcFile.fd, buffer, { offset: offset });
          if (readResult.bytesRead === 0) {
            break;
          }
          fs.writeSync(destFile.fd, buffer, { offset: offset });
          offset += readResult.bytesRead;
        }
        
        // 4. 关闭文件
        fs.closeSync(srcFile);
        fs.closeSync(destFile);
        
        console.log('复制成功,路径:', sandboxPath);
      } catch (err) {
        let error = err as BusinessError;
        console.error('复制失败:', error.code, error.message);
      }
    }
    

关键注意事项

  • 确保在module.json5中声明必要权限:
    {
      "requestPermissions": [
        {
          "name": "ohos.permission.READ_IMAGEVIDEO"
        }
      ]
    }
    
  • 直接使用fs.copy可能因权限不足失败,需通过Uri逐步读写
  • 大文件建议分块读写,避免内存溢出
  • 目标路径需使用应用沙箱路径(filesDircacheDir等)

如果仍遇到问题,请检查:

  1. Uri格式是否正确(应以file://dataability://开头)
  2. 是否已授予媒体文件访问权限
  3. 目标路径是否可写
回到顶部