HarmonyOS鸿蒙Next中文件如何存储的公共目录

HarmonyOS鸿蒙Next中文件如何存储的公共目录

3 回复

【背景知识】

HarmonyOS为应用提供了两种将文件存储到公共目录的方案,解决不同场景应用及用户对文件的使用诉求,同时保障了文件使用的安全性与隐私性。

  • 方案一:下载控件效果介绍。应用存在下载场景时,用户希望将文件下载到指定的本地公共目录。下载控件帮应用在下载目录创建文件夹并完成目录级授权(如:我的手机->下载->XXX),应用可将文件下载到此目录(应用具备此目录读写权限)。目录所有权归用户,应用和用户均可见。

  • 方案二:FilePicker效果介绍:单次保存,每次弹框,目录可选,精准保存

下载控件 FilePicker
权限差异 1、对“下载>xx应用”目录具有长期读写权限
2、本应用仅可访问本应用下载目录(权限限制到应用,防止其他应用恶意删除本应用下载文件)
对用户选择另存为的文件具有长期读写权限(无目录权限,只可读写保存的文件)
保存路径 无法自定义,固定为“下载>xx应用”(目录固定,培养用户习惯,大量下载时便于用户根据应用查找) 用户可选择本地任意目录(目录灵活,适合单次下载精准保存)
处理文件数量 目录权限给应用后,由应用决定,支持一次下载多个文件(大量下载时方便使用) 一次弹框只能保存一个文件(大量下载时,频繁操作,使用繁琐)
弹框差异 无需弹框 (下载体验一步直达) 另存为文件时每次需要弹出FilePicker窗口 (每次弹框,操作繁琐)
重命名或删除目录 URI变化权限清除,需要重新调用下载控件创建目录 URI变化权限清除,需重新调用picker授权
卸载后文件处理 应用卸载后,下载目录不会删除 (保证用户文件不丢失) 应用卸载后,另存为文件不会删除 (保证用户文件不丢失)

【解决方案】

推荐应用接入下载控件,参考demo如下:

import picker from '@ohos.file.picker';
import fs from '@ohos.file.fs';
import { BusinessError } from '@ohos.base';
import common from '@ohos.app.ability.common';
import FileUri from '@ohos.file.fileuri';
import { DownloadDescription, DownloadFileButton, DownloadIconStyle,
  DownloadLayoutDirection } from '@ohos.arkui.advanced.DownloadFileButton';
const documentSaveOptions = new picker.DocumentSaveOptions();
documentSaveOptions.pickerMode = picker.DocumentPickerMode.DOWNLOAD;

@Entry
@Component
struct Index {
  @State message: string = 'Hello World';
  @State text: string = '';
  controller: TextInputController = new TextInputController();
  private constUri: string = '';

  build() {
    Row() {
      Column() {
        Text('方式一: 使用ICON控件')
          .fontSize(20)
          .border({ width: 1 })
          .borderRadius(10)
          .lineHeight(28)
          .margin(30)
        Row() {
          Text('输入文件名: ')
            .fontSize(20)
            .border({ width: 1 })
            .borderRadius(10)
            .lineHeight(28)
            .margin(10)
          TextInput({ text: this.text, placeholder: 'examples.doc', controller: this.controller })
            .placeholderColor(Color.Grey)
            .placeholderFont({ size: 20, weight: 150 })
            .caretColor(Color.Blue)
            .width('50%')
            .height(40)
            .margin(30)
            .fontSize(16).fontColor(Color.Black)
            .onChange((value: string) => {
              this.text = value
            })
        }
        // 标准下载icon控件
        DownloadFileButton({
          contentOptions: { // 指定元素内容下载按钮
            icon: DownloadIconStyle.FULL_FILLED,
            text: DownloadDescription.DOWNLOAD
          },
          styleOptions: { // 指定元素样式的下载按钮
            iconSize: '20vp',
            layoutDirection: DownloadLayoutDirection.VERTICAL,
            fontSize: '16vp',
            fontStyle: FontStyle.Normal,
            fontWeight: FontWeight.Medium,
            fontFamily: 'HarmonyOS Sans',
            fontColor: '#ffffffff',
            iconColor: '#ffffffff',
            textIconSpace: '4vp'
          }
        })
          // .backgroundColor('#007dff')
          .onClick(() => {
            this.downloadAction();
          })

        Text('方式二: 使用DocumentViewPicker')
          .fontSize(20)
          .border({ width: 1 })
          .borderRadius(10)
          .lineHeight(28)
          .margin(30)
        Row() {
          Text('输入文件名: ')
            .fontSize(20)
            .border({ width: 1 })
            .borderRadius(10)
            .lineHeight(28)
            .margin(10)
          TextInput({ text: this.text, placeholder: 'examples.doc', controller: this.controller })
            .placeholderColor(Color.Grey)
            .placeholderFont({ size: 20, weight: 150 })
            .caretColor(Color.Blue)
            .width('50%')
            .height(40)
            .margin(30)
            .fontSize(16)
            .fontColor(Color.Black)
            .onChange((value: string) => {
              this.text = value
            })
        }

        // 三方自定义/框架的下载界面
        Button("下载")
          .onClick(() => {
            this.downloadAction();
          })
      }
      .width('100%')
    }
    .height('100%')
    .backgroundColor($r('sys.color.ohos_id_color_sub_background'))
  }

  downloadAction() {
    let filePath = new FileUri.FileUri(this.constUri).path;
    filePath = filePath.replace('/data/storage/el2/share/rw/docs', '');
    console.error(`this.constUri: ` + this.constUri + filePath);
    // 判断应用专属目录是否存在
    if (!fs.accessSync(filePath)) {
      // 不存在拉起弹窗,创建应用专属目录,返回uri
      this.creatFolderAndGrant();
    } else {
      // 存在则将文件保存在该URI下
      this.writeFileInFolder(this.constUri);
    }
  }

  creatFolderAndGrant() {
    let context = getContext(this) as common.Context;
    const documentViewPicker = new picker.DocumentViewPicker(context);
    // 创建文件管理器选项实例
    const documentSaveOptions = new picker.DocumentSaveOptions();
    // 配置保存的模式为DOWNLOAD
    documentSaveOptions.pickerMode = picker.DocumentPickerMode.DOWNLOAD;
    // save接口拉起弹窗,点击同意,返回应用专属目录uri
    documentViewPicker.save(documentSaveOptions ).then((documentSaveResult: Array<string>) => {
      console.error(`documentViewPicker ` + documentSaveResult[0]);
      let uri = documentSaveResult[0];
      // 保存应用专属目录uri,后续用户可以直接将文件保存在该URI下
      this.constUri = uri;
    }).catch((err: BusinessError) => {
      console.error(`Invoke documentViewPicker.save failed, code is ${err.code}, message is ${err.message}`);
    })
  }

  async writeFileInFolder(uri: string) {
    try {
      let path: string = new FileUri.FileUri(uri).path
      let filePath: string = `${path}/${this.text}`;

      // 测试权限并创建
      const testCreateFile = await fs.open(filePath, fs.OpenMode.CREATE)
        .catch((err: string) => console.error(`Invoke documentViewPicker.save failed`));
      if (testCreateFile) {
        fs.closeSync(testCreateFile.fd);
      }
      let fileContent = 'Hello, world!';
      let createRes: fs.File | BusinessError = fs.openSync(filePath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
      fs.writeSync(createRes.fd, fileContent);
      fs.closeSync(createRes);
    } catch (err) {
      console.error(`create file failed, code is ${err.code}, message is ${err.message}`);
    }
  }
}

更多关于HarmonyOS鸿蒙Next中文件如何存储的公共目录的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


HarmonyOS Next的文件存储采用应用沙箱机制,公共目录通过特定URI访问。用户文件存储在媒体库,包括图片、视频、音频和文档目录,通过PhotoViewPicker等选择器获取访问权限。下载文件存放于Download目录。应用数据存储在沙箱内,外部访问需授权。文件管理遵循分类存储原则,不同类型文件对应不同目录路径,确保数据隔离与安全。

在HarmonyOS Next中,文件存储的公共目录主要通过应用沙箱和公共数据访问权限实现。系统为每个应用分配独立的沙箱目录(如/data/storage/el1/bundle),用于私有数据存储。若需访问公共目录(如相册、下载文件夹),需通过FileManager API并申请相应权限(如ohos.permission.READ_IMAGEVIDEO)。例如,使用getPublicDirectory()方法可获取公共路径,但需注意权限管理和用户授权流程。具体实现可参考官方文档的FileManager模块说明。

回到顶部