开源 Arkts 鸿蒙应用 开发(六)数据持久--文件和首选项存储

文章的目的为了记录使用Arkts 进行Harmony app 开发学习的经历。本职为嵌入式软件开发,公司安排开发app,临时学习,完成app的开发。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。

相关链接:

开源 Arkts 鸿蒙应用 开发(一)工程文件分析-CSDN博客

开源 Arkts 鸿蒙应用 开发(二)封装库.har制作和应用-CSDN博客

开源 Arkts 鸿蒙应用 开发(三)Arkts的介绍-CSDN博客

开源 Arkts 鸿蒙应用 开发(四)布局和常用控件-CSDN博客

开源 Arkts 鸿蒙应用 开发(五)控件组成和复杂控件-CSDN博客

推荐链接:

开源 java android app 开发(一)开发环境的搭建-CSDN博客

开源 java android app 开发(二)工程文件结构-CSDN博客

开源 java android app 开发(三)GUI界面布局和常用组件-CSDN博客

开源 java android app 开发(四)GUI界面重要组件-CSDN博客

开源 java android app 开发(五)文件和数据库存储-CSDN博客

开源 java android app 开发(六)多媒体使用-CSDN博客

开源 java android app 开发(七)通讯之Tcp和Http-CSDN博客

开源 java android app 开发(八)通讯之Mqtt和Ble-CSDN博客

开源 java android app 开发(九)后台之线程和服务-CSDN博客

开源 java android app 开发(十)广播机制-CSDN博客

开源 java android app 开发(十一)调试、发布-CSDN博客

开源 java android app 开发(十二)封库.aar-CSDN博客

推荐链接:

开源C# .net mvc 开发(一)WEB搭建_c#部署web程序-CSDN博客

开源 C# .net mvc 开发(二)网站快速搭建_c#网站开发-CSDN博客

开源 C# .net mvc 开发(三)WEB内外网访问(VS发布、IIS配置网站、花生壳外网穿刺访问)_c# mvc 域名下不可訪問內網,內網下可以訪問域名-CSDN博客

开源 C# .net mvc 开发(四)工程结构、页面提交以及显示_c#工程结构-CSDN博客

开源 C# .net mvc 开发(五)常用代码快速开发_c# mvc开发-CSDN博客

本章节内容如下:

  1. 文件存储

  2. 首选项存储

一、文件读写,实现了按键将对话框数据对写入文件,按键读取文件数据到对话框。写入后,关闭app,重新打开后再读出,验证文件存取成功。

1.1 写入文件和读出文件代码

复制代码
writeToFile() {
    try {
      let file = fs.openSync(this.filePath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
      fs.writeSync(file.fd, this.inputText);
      fs.closeSync(file.fd);
      this.outputText = '内容已成功写入文件';
      console.log('写入文件成功');
    } catch (error) {
      console.error(`写入文件失败: ${error.message}`);
      this.outputText = '写入文件失败';
    }
  }

  readFromFile() {
    try {
      if (!fs.accessSync(this.filePath)) {
        this.outputText = '文件不存在';
        return;
      }

      let file = fs.openSync(this.filePath, fs.OpenMode.READ_ONLY);
      let stat = fs.statSync(this.filePath);
      let arrayBuffer = new ArrayBuffer(stat.size);
      fs.readSync(file.fd, arrayBuffer);
      fs.closeSync(file.fd);

      // 使用循环将Uint8Array转换为字符串
      const uint8Array = new Uint8Array(arrayBuffer);
      let result = '';
      for (let i = 0; i < uint8Array.length; i++) {
        result += String.fromCharCode(uint8Array[i]);
      }
      this.outputText = result;
    } catch (error) {
      console.error(`读取文件失败: ${error.message}`);
      this.outputText = '读取文件失败';
    }
  }

1.2 界面代码

复制代码
build() {
    Column({ space: 20 }) {
      TextInput({ placeholder: '请输入要保存的内容' })
        .width('90%')
        .height(60)
        .onChange((value: string) => {
          this.inputText = value;
        })

      Button('写入文件')
        .width('60%')
        .height(40)
        .onClick(() => {
          this.writeToFile();
        })

      TextInput({ placeholder: '文件内容将显示在这里', text: this.outputText })
        .width('90%')
        .height(60)


      Button('读取文件')
        .width('60%')
        .height(40)
        .onClick(() => {
          this.readFromFile();
        })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }

1.3 \pages\index.ets代码

复制代码
// MainAbility.ets
import common from '@ohos.app.ability.common';
import fs from '@ohos.file.fs';



@Entry
@Component
struct FileReadWriteExample {
  @State inputText: string = '';
  @State outputText: string = '';
  private context = getContext(this) as common.UIAbilityContext;
  private filePath: string = '';

  aboutToAppear() {
    this.filePath = this.context.filesDir + '/example.txt';

    console.log(`文件路径: ${this.filePath}`);
  }

  writeToFile() {
    try {
      let file = fs.openSync(this.filePath, fs.OpenMode.CREATE | fs.OpenMode.READ_WRITE);
      fs.writeSync(file.fd, this.inputText);
      fs.closeSync(file.fd);
      this.outputText = '内容已成功写入文件';
      console.log('写入文件成功');
    } catch (error) {
      console.error(`写入文件失败: ${error.message}`);
      this.outputText = '写入文件失败';
    }
  }

  readFromFile() {
    try {
      if (!fs.accessSync(this.filePath)) {
        this.outputText = '文件不存在';
        return;
      }

      let file = fs.openSync(this.filePath, fs.OpenMode.READ_ONLY);
      let stat = fs.statSync(this.filePath);
      let arrayBuffer = new ArrayBuffer(stat.size);
      fs.readSync(file.fd, arrayBuffer);
      fs.closeSync(file.fd);

      // 使用循环将Uint8Array转换为字符串
      const uint8Array = new Uint8Array(arrayBuffer);
      let result = '';
      for (let i = 0; i < uint8Array.length; i++) {
        result += String.fromCharCode(uint8Array[i]);
      }
      this.outputText = result;
    } catch (error) {
      console.error(`读取文件失败: ${error.message}`);
      this.outputText = '读取文件失败';
    }
  }

  build() {
    Column({ space: 20 }) {
      TextInput({ placeholder: '请输入要保存的内容' })
        .width('90%')
        .height(60)
        .onChange((value: string) => {
          this.inputText = value;
        })

      Button('写入文件')
        .width('60%')
        .height(40)
        .onClick(() => {
          this.writeToFile();
        })

      TextInput({ placeholder: '文件内容将显示在这里', text: this.outputText })
        .width('90%')
        .height(60)


      Button('读取文件')
        .width('60%')
        .height(40)
        .onClick(() => {
          this.readFromFile();
        })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

1.4 演示

二、首选项读写

2.1 页面显示代码index.ets,实现显示3个按钮。

复制代码
// index.ets
@Entry
@Component
struct Index {
  build() {
    Column() {
      Button('Button 1')
        .margin({ top: 10, bottom: 10 })
        .onClick(() => {
          // 通过全局对象调用Ability方法
          if (globalThis.entryAbility?.btn1) {
            globalThis.entryAbility.btn1();
          }
      })
        .width('100%')
      Row()
      Button('Button 2')
        .margin({ top: 10, bottom: 10 })
        .onClick(() => {
          if (globalThis.entryAbility?.btn2) {
            globalThis.entryAbility.btn2();
          }
        })
        .width('100%')

      Button('Button 3')
        .margin({ top: 10, bottom: 10 })
        .onClick(() => {
          if (globalThis.entryAbility?.btn3) {
            globalThis.entryAbility.btn3();
          }
        })
        .width('100%')
    }
    .width('100%')
    .height('100%')
  }
}

2.2 UIAbility的代码EntryAbility.ets,功能包括

初始化Preferences数据存储

提供三个按钮操作:

btn1(): 写入字符串、二进制数据和数字到Preferences

btn2(): 从Preferences读取并显示存储的数据

btn3(): 删除Preferences中的数据

Preferences操作

代码中提供了完整的Preferences CRUD操作:

初始化:initPreferences()异步方法

写入数据:btn1()使用putSync()同步写入三种类型数据、字符串、二进制数据(Uint8Array)、数字

读取数据:btn2()使用getSync()同步读取数据、使用TextDecoder解码二进制数据

删除数据:btn3()使用deleteSync()同步删除数据

Preferences同步/异步操作:

初始化使用异步getPreferences()

数据操作使用同步方法(putSync, getSync, deleteSync)

写入后调用flushSync()确保数据持久化

以下为代码

复制代码
import { AbilityConstant, ConfigurationConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';


import { BusinessError } from '@kit.BasicServicesKit';

import { preferences } from '@kit.ArkData';
import { util } from '@kit.ArkTS';


const DOMAIN = 0x0000;
let dataPreferences: preferences.Preferences | null = null;

export default class EntryAbility extends UIAbility {
  // 初始化Preferences
  async initPreferences(): Promise<void> {
    try {
      let options: preferences.Options = { name: 'myStore' };
      dataPreferences = await preferences.getPreferences(this.context, options);
    } catch (err) {
      hilog.error(DOMAIN, 'testTag', 'Failed to get preferences. Cause: %{public}s', JSON.stringify(err));
    }
  }

  // 按钮1:写入数据
  btn1(): void {
    if (!dataPreferences) {
      console.error('click btn1 Preferences not initialized');
      return;
    }

    try {
      // 写入字符串
      dataPreferences.putSync('string_key', 'Hello ArkTS');

      // 写入Uint8Array
      let encoder = new util.TextEncoder();
      let uInt8Array = encoder.encodeInto("你好,ArkTS");
      dataPreferences.putSync('binary_key', uInt8Array);

      // 写入数字
      dataPreferences.putSync('number_key', 123);

      dataPreferences.flushSync();

      console.info('click btn1 Preferences Data written successfully');
    } catch (err) {
      console.error('click btn1 Preferences Failed to write data: ' + JSON.stringify(err));
    }
  }

  // 按钮2:读取数据
  btn2(): void {
    if (!dataPreferences) {
      console.error('click btn2 Preferences not initialized');
      return;
    }

    try {
      // 读取字符串
      let stringVal = dataPreferences.getSync('string_key', 'default');
      console.info('click btn2 Preferences String value: ' + stringVal);

      // 读取二进制数据
      let binaryVal = dataPreferences.getSync('binary_key', new Uint8Array(0));
      let decoder = new util.TextDecoder('utf-8');
      let decodedStr = decoder.decode(binaryVal as Uint8Array);
      console.info('click btn2 Preferences Binary value: ' + decodedStr);

      // 读取数字
      let numberVal = dataPreferences.getSync('number_key', 0);
      console.info('click btn2 Preferences Number value: ' + numberVal);
    } catch (err) {
      console.error('click btn2 Preferences Failed to read data: ' + JSON.stringify(err));
    }
  }

  // 按钮3:删除数据
  btn3(): void {
    if (!dataPreferences) {
      console.error('click btn3 Preferences not initialized');
      return;
    }

    try {
      dataPreferences.deleteSync('string_key');
      dataPreferences.deleteSync('binary_key');
      dataPreferences.deleteSync('number_key');
      console.info('click btn3 Preferences Data deleted successfully');
    } catch (err) {
      console.error('click btn3 Preferences Failed to delete data: ' + JSON.stringify(err));
    }
  }

  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    this.context.getApplicationContext().setColorMode(ConfigurationConstant.ColorMode.COLOR_MODE_NOT_SET);
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');

    globalThis.abilityContext = this.context;
    globalThis.entryAbility = this;

    // 初始化Preferences
    this.initPreferences();
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    // Main window is created, set main page for this ability
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageCreate');

    windowStage.loadContent('pages/Index', (err) => {
      if (err.code) {
        hilog.error(DOMAIN, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err));
        return;
      }
      hilog.info(DOMAIN, 'testTag', 'Succeeded in loading the content.');
    });

    /*
    let options: preferences.Options = { name: 'myStore' };
    dataPreferences = preferences.getPreferencesSync(this.context, options);


    if (dataPreferences.hasSync('startup')) {
      console.info("The key 'startup' is contained.");
    } else {
      console.info("The key 'startup' does not contain.");
      // 此处以此键值对不存在时写入数据为例
      dataPreferences.putSync('startup', 'auto');
      // 当字符串有特殊字符时,需要将字符串转为Uint8Array类型再存储,长度均不超过16 * 1024 * 1024个字节。
      //let uInt8Array1 = new util.TextEncoder().encodeInto("~!@#¥%......&*()------+?");


      let encoder: util.TextEncoder = new util.TextEncoder();
      let uInt8Array1: Uint8Array = encoder.encodeInto("你好,ArkTS"); // 或 encode()

      dataPreferences.putSync('uInt8', uInt8Array1);
    }

    let val = dataPreferences.getSync('startup', 'default');
    console.info("The 'startup' value is " + val);
    // 当获取的值为带有特殊字符的字符串时,需要将获取到的Uint8Array转换为字符串
    let uInt8Array2 : preferences.ValueType = dataPreferences.getSync('uInt8', new Uint8Array(0));

    let textDecoder = util.TextDecoder.create('utf-8');
    val = textDecoder.decodeToString(uInt8Array2 as Uint8Array);




    console.info("The 'uInt8' value is " + val);

    */
  }

  onWindowStageDestroy(): void {
    // Main window is destroyed, release UI related resources
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');
  }

  onForeground(): void {
    // Ability has brought to foreground
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onForeground');
  }

  onBackground(): void {
    // Ability has back to background
    hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onBackground');
  }
}

2.3 测试效果如下,测试了写入,读出,删除。删除后再读出则为空。

相关推荐
花嫁代二娃4 小时前
Linux:环境变量
linux
爱笑的眼睛118 小时前
08-自然壁纸实战教程-视频列表-云
华为·harmonyos
ai小鬼头9 小时前
AIStarter新版重磅来袭!永久订阅限时福利抢先看
人工智能·开源·github
春哥的研究所9 小时前
可视化DIY小程序工具!开源拖拽式源码系统,自由搭建,完整的源代码包分享
小程序·开源·开源拖拽式源码系统·开源拖拽式源码·开源拖拽式系统
l1x1n010 小时前
Vim 编辑器常用操作详解(新手快速上手指南)
linux·编辑器·vim
ajassi200011 小时前
开源 python 应用 开发(三)python语法介绍
linux·python·开源·自动化
o不ok!11 小时前
Linux面试问题-软件测试
linux·运维·服务器
说私域11 小时前
基于开源AI大模型AI智能名片S2B2C商城小程序源码的私域流量新生态构建
人工智能·开源
qq_3129201111 小时前
开源入侵防御系统——CrowdSec
安全·开源
DaxiaLeeSuper11 小时前
Prometheus+Grafana+node_exporter监控linux服务器资源的方案
linux·grafana·prometheus