HarmonyOS 鸿蒙Next中fileIo.mkdirSync方法报错:fileIo.mkdirSync

HarmonyOS 鸿蒙Next中fileIo.mkdirSync方法报错:fileIo.mkdirSync

fileIo.mkdirSync('/data/account', true)

这行递归创建文件目录的代码报错:Permission denied,请问是需要什么权限嘛,API文档里也没写要申请权限啊,求教

5 回复

可以参考这个沙箱文件使用

【背景知识】

  • 应用沙箱详解

    • 什么是应用沙箱目录?
      • 对于每个应用,系统会在内部存储空间映射出一个专属的“沙箱目录”,应用可见的目录范围即为“应用沙箱目录”。
    • 应用沙箱目录组成?
      • 应用沙箱目录是“应用文件目录”与一部分系统文件(应用运行必需的少量系统文件)所在的目录组成的集合。
    • 应用沙箱作用
      • 应用沙箱限制了应用可见的数据范围。在“应用沙箱目录”中,应用仅能看到自己的应用文件以及少量的系统文件(应用运行必需的少量系统文件)。因此,本应用的文件也不为其他应用可见,从而保护了应用文件的安全。
      • 应用可以在“应用文件目录”下保存和处理自己的应用文件;系统文件及其目录对于应用是只读的;而应用若需访问用户文件,则需要通过特定API同时经过用户的相应授权才能进行。
  • 关系型数据库详解

    • 关系型数据库Relational Database,RDB是一种基于关系模型来管理数据的数据库。关系型数据库基于SQLite组件提供了一套完整的对本地数据库进行管理的机制,对外提供了一系列的增、删、改、查等接口,也可以直接运行用户输入的SQL语句来满足复杂的场景需要。
    • ArkTS提供了@ohos.data.relationalStore包,支持SQLite组件的增、删、改、查,以及通过ResultSet.getSendableRow方法获取Sendable数据,进行跨线程传递等众多通用数据库操作接口。

【解决方案】

基于安全访问要求,目前不支持直接在rawfile目录下去进行读写数据库,数据库文件必须放在数据库相关的沙箱路径及其子目录下,应用才能访问。

如上述情形:将db文件下载到了rawfile目录中,可以考虑将db文件拷贝至数据库存储沙箱路径,再借助@ohos.data.relationalStore包进行数据库处理; 数据库查询参见:【数据库查询访问API参考】;代码处理步骤:

  1. 借助getContext(this).getApplicationContext().databaseDir创建好应用沙箱数据库目录;
  2. 使用getContext(this).resourceManager.getRawFd获取rawfile目录里面的原始数据库文件信息;
  3. 调用saveFileToSandbox将【2】中获取的原始数据库文件写入【1】中已创建好的沙箱数据库目录;

参考如下代码:

import fs, { ReadOptions } from '@ohos.file.fs';
import { resourceManager } from '@kit.LocalizationKit';

@Entry
@Component
struct Index {
  aboutToAppear(): void {
    this.initDataBaseDir();
  }

  build() {
    RelativeContainer() {
      Text('test')
        .id('HelloWorld')
        .fontSize(50)
        .fontWeight(FontWeight.Bold)
        .alignRules({
          center: { anchor: '__container__', align: VerticalAlign.Center },
          middle: { anchor: '__container__', align: HorizontalAlign.Center }
        })
    }
    .height('100%')
    .width('100%')
  }

  saveFileToSandbox(file: resourceManager.RawFileDescriptor, dbName: string) {
    // 创建缓存文件(当前是覆盖式创建)
    let cFile = getContext(this).getApplicationContext().databaseDir + "/entry/rdb/" + dbName
    let cacheFile = fs.openSync(cFile, fs.OpenMode.READ_WRITE | fs.OpenMode.CREATE)

    // 读取缓冲区大小
    let bufferSize = 30000
    let buffer = new ArrayBuffer(bufferSize); // 创建buffer缓冲区

    // 要copy的文件的offset和length
    let currentOffset = file.offset;

    let readOption: ReadOptions = {
      offset: currentOffset, // 期望读取文件的位置。可选,默认从当前位置开始读
      length: bufferSize // 每次期望读取数据的长度。可选,默认缓冲区长度
    }

    // 后面len会一直减,直到没有
    while (true) {
      // 读取buffer容量的内容
      let readLength = fs.readSync(file.fd, buffer, readOption);
      // 写入buffer容量的内容
      // 写到cacheFile里
      fs.writeSync(cacheFile.fd, buffer, { length: readLength }) 
      // 判断后续内容,修改读文件的参数
      // buffer没读满代表文件读完了
      if (readLength < bufferSize) {
        break;
      }
      if (readOption.offset != undefined) {
        readOption.offset += readLength;
      }
    }
    console.log("Copy Success!!!")
    fs.close(cacheFile);
  }

  initDataBaseDir() {
    // 创建数据库沙箱目录
    try {
      let dirPath = getContext(this).getApplicationContext().databaseDir + "/entry"
      fs.mkdirSync(dirPath);
      dirPath = dirPath + "/rdb"
      fs.mkdirSync(dirPath);
    } catch (error) {
      console.error('initDataBaseDir err');
    }

    // 数据库名称
    let dbName: string = 'Company.db'

    // 读取rawfile目录下db文件
    try {
      getContext(this).resourceManager.getRawFd('rdb/' + dbName, (error, value) => {
        if (error != null) {
          console.error('callback getRawFd failed error');
        } else {
          console.info(value.length.toString())
          this.saveFileToSandbox(value, dbName)
        }
      });
    } catch (error) {
      console.error('callback getRawFd failed')
    }
  }
}

更多关于HarmonyOS 鸿蒙Next中fileIo.mkdirSync方法报错:fileIo.mkdirSync的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


看下沙箱文件目录,我们应该使用四级以后的目录,来做文件处理。之前的目录很可能是禁止写入的。

也不推荐直接拼接路径,比如 data/storage/xxx

而是通过上下文去获取沙箱目录,比如:

this.context.filesDir

https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/app-sandbox-directory

懂了,谢啦,

在HarmonyOS鸿蒙Next中,fileIo.mkdirSync报错通常由以下原因导致:

  1. 路径无效或格式错误(需使用应用沙箱路径如this.filesDir + "/newDir"
  2. 目录已存在(需先调用fileIo.accessSync检查)
  3. 权限不足(需在config.json中声明ohos.permission.FILE_ACCESS权限)
  4. 父目录不存在(需确保上级目录存在)

典型错误代码:BusinessError: 13900004表示文件已存在,13900002表示无权限。

在HarmonyOS Next中,/data/account属于系统受保护目录,普通应用默认没有写入权限。即使使用fileIo.mkdirSync方法,也需要先申请相应的存储权限。

建议检查以下两点:

  1. 确保在module.json5中声明了必要的文件访问权限:
"requestPermissions": [
  {
    "name": "ohos.permission.WRITE_USER_STORAGE"
  }
]
  1. 对于系统级目录的访问,普通应用通常只能操作应用沙箱内的目录(如/data/storage/el2/base/haps/your_package_name)。如需访问特殊目录,可能需要更高级别的权限或使用特定的API。

可以尝试改为在应用沙箱目录下创建文件夹,这是推荐的安全做法。

回到顶部