管理中心
我的

如何读写外置存储设备(如U盘)中的文件

问题现象

如何访问外置存储设备的文件?

如何将沙箱内文件拷贝到外置存储设备?

背景知识

  • 三方应用在操作手机文件时,可以通过ohos.file.picker来实现文件的访问。
  • 外置存储设备(例如U盘)上的文件,全部以普通文件的形式呈现,和内置存储设备上的文档类文件一样,采用目录树的形式对外展示。需要使用DocumentViewPicker来实现系统文件的访问。

解决方案

一、访问外置存储设备的文件

  1. 通过picker来访问用户相关文件,拉起对应的应用,引导用户完成界面操作,接口本身无需申请权限。
  2. 外置存储系统文件的访问,先用文件选择器把系统文件夹里的文件拷贝到沙箱,再对沙箱里的文件进行各种操作。
  3. 具体方法是:调用DocumentViewPicker可以实现预览系统文件,再把选中的文件写入到对应的沙箱中。
    收起
    自动换行
    深色代码主题
    复制
    1. import { common } from '@kit.AbilityKit';
    2. import { picker } from '@kit.CoreFileKit';
    3. import { BusinessError } from '@kit.BasicServicesKit';
    4. import fs from '@ohos.file.fs';
    5. @Entry
    6. @Component
    7. struct Index {
    8. build() {
    9. Row() {
    10. Column() {
    11. Button('查看U盘文件并导入到沙箱')
    12. .fontSize(20)
    13. .fontWeight(FontWeight.Bold)
    14. .onClick(() => {
    15. let context = this.getUIContext().getHostContext() as common.Context;
    16. let documentPicker = new picker.DocumentViewPicker(context);
    17. let documentSelectOptions = new picker.DocumentSelectOptions();
    18. // filePathList:选中的文件集合
    19. documentPicker.select(documentSelectOptions).then((filePathList: Array<string>) => {
    20. for (let i = 0; i < filePathList.length; i++) {
    21. let filePath = filePathList[i];
    22. let toPath = this.getUIContext().getHostContext()?.filesDir;
    23. let newFrom = filePath.substring(filePath.lastIndexOf('/'));
    24. toPath = toPath + newFrom;
    25. let fromFile = fs.openSync(filePath, fs.OpenMode.READ_ONLY);
    26. let toFile = fs.openSync(toPath, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE);
    27. fs.copyFileSync(fromFile.fd, toFile.fd, 0);
    28. console.info('成功将[' + filePath + ']文件拷贝到了沙箱');
    29. }
    30. }).catch((err: BusinessError) => {
    31. console.error('DocumentViewPicker.select failed with err: ' + err);
    32. });
    33. });
    34. }
    35. .width('100%');
    36. }
    37. .height('100%');
    38. }
    39. }
  1. 实现效果:
    • 点击查看U盘文件并导入到沙箱按钮后,拉起了DocumentViewPicker。

    • 点击MyUSB后可以浏览我的U盘。选中要拷贝的文件。

    • 点击完成后,成功将U盘中的两个文件拷贝到了沙箱。

二、拷贝文件到外置存储设备的文件

下面以拷贝rawfile文件夹的图片到U盘为例。

  1. 通过fileStream.writeSync将rawfile文件夹递归拷贝到沙箱中。
    收起
    自动换行
    深色代码主题
    复制
    1. copyRawFileToSdcard(context: common.Context) {
    2. let destRoot = context.filesDir;
    3. // rawfile下的文件名
    4. let srcFileName = 'testaaa.jpg';
    5. let destFilePath = destRoot + '/test/' + srcFileName;
    6. // 创建文件目录
    7. fileIo.mkdir(destRoot + '/test').then(async () => {
    8. // 创建目录成功
    9. console.info('copyRawFileToSdcard mkdir success');
    10. context.resourceManager.getRawFileContent(srcFileName, (error: BusinessError, data: Uint8Array) => {
    11. if (error != null) {
    12. promptAction.openToast({ message: '拷贝失败' });
    13. console.error(`error.code is ${error.code},error.message is ${error.message},`);
    14. } else {
    15. let fileStream = fileIo.createStreamSync(destFilePath, 'w+');
    16. fileStream.writeSync(data.buffer);
    17. fileStream.close();
    18. // 文件拷贝成功
    19. promptAction.openToast({ message: '拷贝成功' });
    20. console.info('copyRawFileToSdcard write success');
    21. }
    22. });
    23. }).catch((error: BusinessError) => {
    24. // 可能目录已存在或者没有权限
    25. promptAction.openToast({ message: '拷贝失败' });
    26. console.error(`copyRawFileToSdcard mkdir fail: ${error.code}, ${error.code}`);
    27. });
    28. }
  1. 通过DocumentViewPicker(无需额外申请权限)来拉起访问文件管理,选择存储位置(如U盘),然后把需要存储的沙箱文件写入到对应的设备位置中。
    收起
    自动换行
    深色代码主题
    复制
    1. SaveFile(filePath: string) {
    2. console.info('documentViewPicker SaveFile path: ' + filePath);
    3. if (!fileIo.accessSync(filePath)) {
    4. console.info('SaveFile path cant access: ' + filePath);
    5. return;
    6. }
    7. // 创建文件管理器选项实例
    8. const documentSaveOptions = new picker.DocumentSaveOptions();
    9. documentSaveOptions.newFileNames = ['test.jpg']; // 保存文件名
    10. documentSaveOptions.fileSuffixChoices = ['.jpg']; // 保存文件类型
    11. let uris: Array<string> = [];
    12. const documentViewPicker = new picker.DocumentViewPicker(); // 创建文件选择器实例
    13. documentViewPicker.save(documentSaveOptions).then((documentSaveResult: Array<string>) => {
    14. uris = documentSaveResult;
    15. console.info('documentViewPicker.save to file succeed and uris are:' + uris);
    16. let file = fileIo.openSync(filePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
    17. let uri = uris[0];
    18. let file2 = fileIo.openSync(uri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
    19. fileIo.copyFileSync(file.fd, file2.fd, 0);
    20. fileIo.closeSync(file2);
    21. fileIo.closeSync(file);
    22. }).catch((err: BusinessError) => {
    23. console.error(`Invoke documentViewPicker.save failed, code is ${err.code}, message is ${err.message}`);
    24. });
    25. }
  2. 完整示例代码:
    收起
    自动换行
    深色代码主题
    复制
    1. import { common } from '@kit.AbilityKit';
    2. import { BusinessError } from '@kit.BasicServicesKit';
    3. import { fileIo, picker } from '@kit.CoreFileKit';
    4. import { promptAction } from '@kit.ArkUI';
    5. @Entry
    6. @Component
    7. struct Index {
    8. private message: string = 'copyImg';
    9. private context = this.getUIContext().getHostContext() as common.UIAbilityContext;
    10. aboutToAppear(): void {
    11. this.copyRawFileToSdcard(this.context);
    12. }
    13. build() {
    14. Row() {
    15. Column() {
    16. Button(this.message)
    17. .fontSize($r('app.float.page_text_font_size'))
    18. .fontWeight(FontWeight.Bold)
    19. .onClick(() => {
    20. let filePath: string = this.context.filesDir + '/test/testaaa.jpg';
    21. this.SaveFile(filePath);
    22. });
    23. }
    24. .width('100%');
    25. }
    26. .height('100%');
    27. }
    28. SaveFile(filePath: string) {
    29. console.info('documentViewPicker SaveFile path: ' + filePath);
    30. if (!fileIo.accessSync(filePath)) {
    31. console.info('SaveFile path cant access: ' + filePath);
    32. return;
    33. }
    34. // 创建文件管理器选项实例
    35. const documentSaveOptions = new picker.DocumentSaveOptions();
    36. documentSaveOptions.newFileNames = ['test.jpg']; // 保存文件名
    37. documentSaveOptions.fileSuffixChoices = ['.jpg']; // 保存文件类型
    38. let uris: Array<string> = [];
    39. const documentViewPicker = new picker.DocumentViewPicker(); // 创建文件选择器实例
    40. documentViewPicker.save(documentSaveOptions).then((documentSaveResult: Array<string>) => {
    41. uris = documentSaveResult;
    42. console.info('documentViewPicker.save to file succeed and uris are:' + uris);
    43. let file = fileIo.openSync(filePath, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
    44. let uri = uris[0];
    45. let file2 = fileIo.openSync(uri, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);
    46. fileIo.copyFileSync(file.fd, file2.fd, 0);
    47. fileIo.closeSync(file2);
    48. fileIo.closeSync(file);
    49. }).catch((err: BusinessError) => {
    50. console.error(`Invoke documentViewPicker.save failed, code is ${err.code}, message is ${err.message}`);
    51. });
    52. }
    53. copyRawFileToSdcard(context: common.Context) {
    54. let destRoot = context.filesDir;
    55. // rawfile下的文件名
    56. let srcFileName = 'testaaa.jpg';
    57. let destFilePath = destRoot + '/test/' + srcFileName;
    58. // 创建文件目录
    59. fileIo.mkdir(destRoot + '/test').then(async () => {
    60. // 创建目录成功
    61. console.info('copyRawFileToSdcard mkdir success');
    62. context.resourceManager.getRawFileContent(srcFileName, (error: BusinessError, data: Uint8Array) => {
    63. if (error != null) {
    64. promptAction.openToast({ message: '拷贝失败' });
    65. console.error(`error.code is ${error.code},error.message is ${error.message},`);
    66. } else {
    67. let fileStream = fileIo.createStreamSync(destFilePath, 'w+');
    68. fileStream.writeSync(data.buffer);
    69. fileStream.close();
    70. // 文件拷贝成功
    71. promptAction.openToast({ message: '拷贝成功' });
    72. console.info('copyRawFileToSdcard write success');
    73. }
    74. });
    75. }).catch((error: BusinessError) => {
    76. // 可能目录已存在或者没有权限
    77. promptAction.openToast({ message: '拷贝失败' });
    78. console.error(`copyRawFileToSdcard mkdir fail: ${error.code}, ${error.code}`);
    79. });
    80. }
    81. }