鸿蒙ohos ArkTS 之 读取本地数据库db文件

914 阅读3分钟
  • 使用的是 ohos自身的 relationalStore
  • 思路: 项目内置db文件 -- 读取db文件 -- 复制到缓存中 -- relationalStore打开数据库

1. 首先把数据库文件放到指定位置,如图所示

WeChat886c45fc34335c1d0199f5b9a159242a.jpg

2. 创建单例来控制数据库

  • 请查看下面的代码

3. 创建db缓存文件夹

  • 数据库 必须写入 /entry/rdb/ 文件中,否则无法读取成功
  • 具体路径请查看下面 initFiles 方法

4. 读取db文件 -- 复制到缓存中

  • 请查看下面的代码saveFileToCache方法
  • 需注意的是 bufferSize 字段,我改成 30000000 后才能被成功读取出来,这个bug困扰了我一整天

5. 获取数据库实例,读取内容

  • 请查看下面的代码 getRDB 方法
  • getRdbStore 方法是连接或创建数据库,如果缓存的数据库有问题或名字对不上,就会创建一个空数据库
  • store.querySql 是读取内容,我当前用来检测读取的是缓存数据库,还是创建了一个新的数据库
  • 现存问题是,读取到的内容里,无法直接获取到某一行的所有数据,只能单个查询某一行中某一列的数据,这是真的废,各位如果有能获取整行数据的方法请务必告诉我

--------------代码如下--------------


// 本地缓存  https://blog.csdn.net/2401_82546228/article/details/138718648
import fs from '@ohos.file.fs';
import { common } from '@kit.AbilityKit';
import { fileIo, ReadOptions } from '@kit.CoreFileKit';
import { resourceManager } from '@kit.LocalizationKit';
import { relationalStore } from '@kit.ArkData';
import { formInfo } from '@kit.FormKit';
import map from '@hms.core.map.map';

export class DBManager {
  private static instanceDB: DBManager;

  private constructor() {
    // 私有构造函数
  }

  public static instance(): DBManager {
    if (!DBManager.instanceDB) {
      DBManager.instanceDB = new DBManager();
    }
    return DBManager.instanceDB;
  }

  private context = getContext(this) as common.UIAbilityContext;
  private resource = (getContext(this) as common.UIAbilityContext).resourceManager;
  private RDBDirectory = (getContext(this) as common.UIAbilityContext).getApplicationContext().databaseDir;
  private dbName = 'jkjlem.db';
  private db: relationalStore.RdbStore | undefined;
  init() {
    console.info('🐯 DB init');
    this.initFiles();
    // this.getRDB();

  }

  getRDB() {
    const STORE_CONFIG: relationalStore.StoreConfig = {
      name: this.dbName,
      securityLevel: relationalStore.SecurityLevel.S1,
    };
    relationalStore.AssetStatus
    relationalStore.getRdbStore(this.context, STORE_CONFIG, (err, store) => {
      if (err) {
        console.error(`🐯 DB 获取数据库失败. Code:${err.code}, message:${err.message}`);
        return;
      } else {
        console.info(`🐯 DB 获取数据库成功.`);
        this.db = store;
        if (this.db != undefined) {

          store.querySql('SELECT * FROM quiz where sub_id = 10425',(err, resultSet) => {
            if (err) {
              console.error(`🐯 DB sql查询失败, code is ${err.code},message is ${err.message}`);
              return;
            }

            console.info(`🐯 DB sql查询 column names: ${resultSet.columnNames}`);
            console.info(`🐯 DB sql查询 column count: ${resultSet.columnCount}`);
            console.info(`🐯 DB sql查询 row count: ${resultSet.rowCount}`);
            console.info(`🐯 DB sql查询 row index: ${resultSet.rowIndex}`);

            // resultSet.goToRow(0);
            // let res = resultSet.getValue(2);
            // console.info(`🐯 DB sql查询 row index: ${res}`);


            for (let r = 0; r < resultSet.rowCount; r++) {
              interface Asset {
                name: string;
                uri: string;
                path: string;
                createTime: string;
                modifyTime: string;
                size: string;
                status?: relationalStore.AssetStatus;
              }
              type Assets = Asset[];
              type ValueType = null | number | string | boolean | Uint8Array | Asset | Assets | Float32Array | bigint;
              let rowDic:Map<string,ValueType> = new Map<string,ValueType>();

              resultSet.goToRow(r);
              for (let c = 0; c < resultSet.columnCount; c++) {
                let res = resultSet.getValue(c);
                rowDic.set(resultSet.columnNames[c],res);
                console.info(`🐯 DB ${resultSet.columnNames[c]} = ${res}`);
              }

              //let ressss = JSON.stringify(rowDic);
              console.info(`🐯 DB sql查询  ${rowDic.get('sub_Titles')}`);

              if (r == resultSet.rowCount-1) {
                resultSet.close();
              }
            }

          });

        }
      }
    })
  }

  initFiles() {
    // 创建数据库沙箱目录
    try {
      let dirPath = this.RDBDirectory + '/entry';

      if (fs.accessSync(dirPath)) {
        console.info(`🐯 DB entry文件夹 已存在`);
      }else{
        fileIo.mkdirSync(dirPath);
        console.error(`🐯 DB entry文件夹 不存在 创建`);
      }

      dirPath = dirPath + '/rdb';

      if (fs.accessSync(dirPath)) {
        console.info(`🐯 DB rdb文件夹 已存在`);
      }else{
        fileIo.mkdirSync(dirPath);
        console.error(`🐯 DB rdb文件夹 不存在 创建`);
      }

      dirPath = dirPath + '/' + this.dbName;
      if (fs.statSync(dirPath)) {
        console.info(`🐯 DB 数据库缓存 已存在`);

        const stats = fs.statSync(dirPath);
        if (stats.isFile()) {
          console.info(`🐯 DB 数据库文件大小: ${stats.size} 字节`);
        } else {
          console.error(`🐯 DB 给定的路径不是一个文件`);
        }
        this.getRDB();

        return;
      }else{
        console.error(`🐯 DB 数据库缓存 不存在 创建`);
      }

    } catch (error) {
      console.error(`🐯 DB 创建数据库沙箱目录失败 或 未查到db文件, error code: ${error.code}, message: ${error.message}.`);
    }


    //读取rawfile目录下db文件
    try {
      this.resource.getRawFd( this.dbName, (error, value) => {
        if (error != null) {
          console.log(`🐯 DB 11callback getRawFd failed error code: ${error.code}, message: ${error.message}.`);
        } else {
          console.info('🐯 DB rawfile中的文件大小' + value.length.toString());
          this.saveFileToCache(value, this.dbName);

        }
      });
    } catch (error) {
      console.error(`🐯 DB 22callback getRawFd failed, error code: ${error.code}, message: ${error.message}.`);
    }
  }



  saveFileToCache(file: resourceManager.RawFileDescriptor, dbName: string) {
    // 创建缓存文件(当前是覆盖式创建)
    let cFile = this.RDBDirectory + '/entry/rdb/' + dbName;
    let cacheFile = fileIo.openSync(cFile, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);

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

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

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

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

    this.getRDB();
  }

}