发布于 2025-09-01
数据存储
HarmonyOS
学习目标
通过本教程,你将学会:
- 理解 HarmonyOS 的数据存储方式
- 掌握 Preferences 的使用(轻量级存储)
- 学会文件存储操作
- 掌握关系型数据库的使用
- 了解数据加密和安全
前置知识
- 完成网络请求
- 了解基本的数据存储概念
核心概念
数据存储方式
HarmonyOS 提供多种数据存储方式:
- Preferences - 轻量级键值对存储(类似 Web 的 localStorage)
- 文件存储 - 文件系统操作
- 关系型数据库 - SQLite 数据库
对比 Web 开发:
localStorage→ PreferencesFile API→ 文件存储 APIIndexedDB→ 关系型数据库
详细内容
1. Preferences(轻量级存储)
基本使用
import dataPreferences from "@ohos.data.preferences";
// 获取 Preferences 实例
async function getPreferences(
context: Context,
name: string
): Promise<dataPreferences.Preferences> {
return await dataPreferences.getPreferences(context, name);
}
// 存储数据
async function saveData() {
let prefs = await dataPreferences.getPreferences(getContext(this), "myPrefs");
// 存储字符串
await prefs.put("username", "Tom");
// 存储数字
await prefs.put("age", 20);
// 存储布尔值
await prefs.put("isLoggedIn", true);
// 存储对象(需要序列化)
await prefs.put("user", JSON.stringify({ name: "Tom", age: 20 }));
// 提交更改
await prefs.flush();
}
// 读取数据
async function loadData() {
let prefs = await dataPreferences.getPreferences(getContext(this), "myPrefs");
// 读取字符串(提供默认值)
let username = await prefs.get("username", "");
// 读取数字
let age = await prefs.get("age", 0);
// 读取布尔值
let isLoggedIn = await prefs.get("isLoggedIn", false);
// 读取对象
let userStr = await prefs.get("user", "{}");
let user = JSON.parse(userStr);
return { username, age, isLoggedIn, user };
}
// 删除数据
async function deleteData() {
let prefs = await dataPreferences.getPreferences(getContext(this), "myPrefs");
await prefs.delete("username");
await prefs.flush();
}
// 清空所有数据
async function clearData() {
let prefs = await dataPreferences.getPreferences(getContext(this), "myPrefs");
await prefs.clear();
await prefs.flush();
}对比 Web 开发:类似 localStorage.setItem() 和 localStorage.getItem()
封装 Preferences 工具类
import dataPreferences from '@ohos.data.preferences';
import { getContext } from '@ohos.ability.common';
class PreferencesManager {
private static instance: PreferencesManager;
private prefs: dataPreferences.Preferences | null = null;
private context: Context;
private constructor(context: Context) {
this.context = context;
}
static async getInstance(context: Context): Promise<PreferencesManager> {
if (!PreferencesManager.instance) {
PreferencesManager.instance = new PreferencesManager(context);
await PreferencesManager.instance.init();
}
return PreferencesManager.instance;
}
private async init(): Promise<void> {
this.prefs = await dataPreferences.getPreferences(this.context, 'app_prefs');
}
async setString(key: string, value: string): Promise<void> {
if (this.prefs) {
await this.prefs.put(key, value);
await this.prefs.flush();
}
}
async getString(key: string, defaultValue: string = ''): Promise<string> {
if (this.prefs) {
return await this.prefs.get(key, defaultValue);
}
return defaultValue;
}
async setNumber(key: string, value: number): Promise<void> {
if (this.prefs) {
await this.prefs.put(key, value);
await this.prefs.flush();
}
}
async getNumber(key: string, defaultValue: number = 0): Promise<number> {
if (this.prefs) {
return await this.prefs.get(key, defaultValue);
}
return defaultValue;
}
async setBoolean(key: string, value: boolean): Promise<void> {
if (this.prefs) {
await this.prefs.put(key, value);
await this.prefs.flush();
}
}
async getBoolean(key: string, defaultValue: boolean = false): Promise<boolean> {
if (this.prefs) {
return await this.prefs.get(key, defaultValue);
}
return defaultValue;
}
async setObject<T>(key: string, value: T): Promise<void> {
await this.setString(key, JSON.stringify(value));
}
async getObject<T>(key: string, defaultValue: T): Promise<T> {
let str = await this.getString(key, '');
if (str) {
return JSON.parse(str) as T;
}
return defaultValue;
}
async remove(key: string): Promise<void> {
if (this.prefs) {
await this.prefs.delete(key);
await this.prefs.flush();
}
}
async clear(): Promise<void> {
if (this.prefs) {
await this.prefs.clear();
await this.prefs.flush();
}
}
}
// 使用示例
@Entry
@Component
struct StorageExample {
private prefsManager: PreferencesManager | null = null;
@State username: string = '';
async aboutToAppear() {
this.prefsManager = await PreferencesManager.getInstance(getContext(this));
this.username = await this.prefsManager.getString('username', '');
}
async saveUsername() {
if (this.prefsManager) {
await this.prefsManager.setString('username', this.username);
}
}
build() {
Column() {
TextInput({ text: this.username, placeholder: 'Username' })
.onChange((value: string) => {
this.username = value;
})
Button('Save')
.onClick(() => {
this.saveUsername();
})
}
}
}2. 文件存储
基本文件操作
import fs from "@ohos.file.fs";
import { getContext } from "@ohos.ability.common";
// 获取文件目录
function getFilesDir(context: Context): string {
return context.filesDir;
}
// 写入文件
async function writeFile(filename: string, content: string): Promise<void> {
let context = getContext(this);
let filePath = context.filesDir + "/" + filename;
let file = await fs.open(
filePath,
fs.OpenMode.CREATE | fs.OpenMode.WRITE_ONLY
);
await fs.write(file.fd, content);
await fs.close(file);
}
// 读取文件
async function readFile(filename: string): Promise<string> {
let context = getContext(this);
let filePath = context.filesDir + "/" + filename;
let file = await fs.open(filePath, fs.OpenMode.READ_ONLY);
let stat = await fs.stat(filePath);
let buffer = new ArrayBuffer(stat.size);
await fs.read(file.fd, buffer);
await fs.close(file);
return new TextDecoder().decode(buffer);
}
// 检查文件是否存在
async function fileExists(filename: string): Promise<boolean> {
let context = getContext(this);
let filePath = context.filesDir + "/" + filename;
try {
await fs.access(filePath);
return true;
} catch {
return false;
}
}
// 删除文件
async function deleteFile(filename: string): Promise<void> {
let context = getContext(this);
let filePath = context.filesDir + "/" + filename;
await fs.unlink(filePath);
}
// 列出目录文件
async function listFiles(dirPath: string): Promise<string[]> {
let dir = await fs.opendir(dirPath);
let files: string[] = [];
for await (let entry of dir) {
files.push(entry.name);
}
await dir.close();
return files;
}文件工具类封装
import fs from "@ohos.file.fs";
import { getContext } from "@ohos.ability.common";
class FileManager {
private context: Context;
constructor(context: Context) {
this.context = context;
}
private getFilePath(filename: string): string {
return this.context.filesDir + "/" + filename;
}
async writeText(filename: string, content: string): Promise<void> {
let filePath = this.getFilePath(filename);
let file = await fs.open(
filePath,
fs.OpenMode.CREATE | fs.OpenMode.WRITE_ONLY | fs.OpenMode.TRUNC
);
await fs.write(file.fd, content);
await fs.close(file);
}
async readText(filename: string): Promise<string> {
let filePath = this.getFilePath(filename);
let file = await fs.open(filePath, fs.OpenMode.READ_ONLY);
let stat = await fs.stat(filePath);
let buffer = new ArrayBuffer(stat.size);
await fs.read(file.fd, buffer);
await fs.close(file);
return new TextDecoder().decode(buffer);
}
async writeJSON<T>(filename: string, data: T): Promise<void> {
await this.writeText(filename, JSON.stringify(data));
}
async readJSON<T>(filename: string): Promise<T | null> {
try {
let content = await this.readText(filename);
return JSON.parse(content) as T;
} catch {
return null;
}
}
async exists(filename: string): Promise<boolean> {
try {
await fs.access(this.getFilePath(filename));
return true;
} catch {
return false;
}
}
async delete(filename: string): Promise<void> {
await fs.unlink(this.getFilePath(filename));
}
}3. 关系型数据库
数据库基本操作
import relationalStore from "@ohos.data.relationalStore";
interface User {
id?: number;
name: string;
email: string;
age: number;
}
class DatabaseManager {
private rdbStore: relationalStore.RdbStore | null = null;
private context: Context;
constructor(context: Context) {
this.context = context;
}
// 初始化数据库
async initDatabase(): Promise<void> {
const config: relationalStore.StoreConfig = {
name: "user.db",
securityLevel: relationalStore.SecurityLevel.S1,
};
this.rdbStore = await relationalStore.getRdbStore(this.context, config);
// 创建表
const sql = `CREATE TABLE IF NOT EXISTS user (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT NOT NULL,
email TEXT UNIQUE,
age INTEGER
)`;
await this.rdbStore.executeSql(sql);
}
// 插入数据
async insertUser(user: User): Promise<number> {
if (!this.rdbStore) {
await this.initDatabase();
}
const valueBucket: relationalStore.ValuesBucket = {
name: user.name,
email: user.email,
age: user.age,
};
return await this.rdbStore!.insert("user", valueBucket);
}
// 查询数据
async queryUsers(): Promise<User[]> {
if (!this.rdbStore) {
await this.initDatabase();
}
const predicates = new relationalStore.RdbPredicates("user");
const resultSet = await this.rdbStore!.query(predicates, [
"id",
"name",
"email",
"age",
]);
let users: User[] = [];
while (resultSet.goToNextRow()) {
users.push({
id: resultSet.getLong(resultSet.getColumnIndex("id")),
name: resultSet.getString(resultSet.getColumnIndex("name")),
email: resultSet.getString(resultSet.getColumnIndex("email")),
age: resultSet.getLong(resultSet.getColumnIndex("age")),
});
}
resultSet.close();
return users;
}
// 更新数据
async updateUser(id: number, user: Partial<User>): Promise<number> {
if (!this.rdbStore) {
await this.initDatabase();
}
const predicates = new relationalStore.RdbPredicates("user");
predicates.equalTo("id", id);
const valueBucket: relationalStore.ValuesBucket = {};
if (user.name) valueBucket["name"] = user.name;
if (user.email) valueBucket["email"] = user.email;
if (user.age !== undefined) valueBucket["age"] = user.age;
return await this.rdbStore!.update(valueBucket, predicates);
}
// 删除数据
async deleteUser(id: number): Promise<number> {
if (!this.rdbStore) {
await this.initDatabase();
}
const predicates = new relationalStore.RdbPredicates("user");
predicates.equalTo("id", id);
return await this.rdbStore!.delete(predicates);
}
}实践练习
练习 1:实现用户设置存储
目标:使用 Preferences 存储用户设置
要求:
- 存储主题设置(light/dark)
- 存储语言设置
- 提供读取和更新方法
参考代码:
class SettingsManager {
private prefs: PreferencesManager;
constructor(context: Context) {
this.prefs = PreferencesManager.getInstance(context);
}
async getTheme(): Promise<string> {
return await this.prefs.getString("theme", "light");
}
async setTheme(theme: string): Promise<void> {
await this.prefs.setString("theme", theme);
}
async getLanguage(): Promise<string> {
return await this.prefs.getString("language", "zh");
}
async setLanguage(lang: string): Promise<void> {
await this.prefs.setString("language", lang);
}
}练习 2:实现笔记应用数据存储
目标:使用文件存储实现简单的笔记应用
要求:
- 保存笔记到文件
- 读取笔记列表
- 删除笔记
参考代码:
interface Note {
id: string;
title: string;
content: string;
createdAt: number;
}
class NoteManager {
private fileManager: FileManager;
private notesFile = "notes.json";
constructor(context: Context) {
this.fileManager = new FileManager(context);
}
async saveNote(note: Note): Promise<void> {
let notes = await this.getNotes();
let index = notes.findIndex((n) => n.id === note.id);
if (index >= 0) {
notes[index] = note;
} else {
notes.push(note);
}
await this.fileManager.writeJSON(this.notesFile, notes);
}
async getNotes(): Promise<Note[]> {
let notes = await this.fileManager.readJSON<Note[]>(this.notesFile);
return notes || [];
}
async deleteNote(id: string): Promise<void> {
let notes = await this.getNotes();
notes = notes.filter((n) => n.id !== id);
await this.fileManager.writeJSON(this.notesFile, notes);
}
}练习 3:实现用户数据库操作
目标:使用关系型数据库管理用户数据
要求:
- 创建用户表
- 实现 CRUD 操作
- 实现查询功能
参考代码:
@Entry
@Component
struct UserDBPage {
private dbManager: DatabaseManager;
@State users: User[] = [];
aboutToAppear() {
this.dbManager = new DatabaseManager(getContext(this));
this.loadUsers();
}
async loadUsers() {
this.users = await this.dbManager.queryUsers();
}
async addUser() {
await this.dbManager.insertUser({
name: 'New User',
email: 'user@example.com',
age: 25
});
await this.loadUsers();
}
build() {
Column() {
Button('Add User')
.onClick(() => {
this.addUser();
})
List() {
ForEach(this.users, (user: User) => {
ListItem() {
Text(`${user.name} - ${user.email}`)
}
})
}
}
}
}常见问题
Q1: Preferences 和文件存储的区别?
A:
- Preferences: 适合存储简单的键值对数据,性能好
- 文件存储: 适合存储复杂数据或大量数据
Q2: 数据库和文件存储如何选择?
A:
- 数据库: 需要复杂查询、关系数据时使用
- 文件存储: 简单数据、配置文件时使用
Q3: 如何实现数据加密?
A: 使用 SecurityLevel.S1 或更高安全级别,或使用加密库对敏感数据进行加密。
Q4: 数据存储在哪里?
A:
- Preferences: 应用私有目录
- 文件: 应用文件目录(filesDir)
- 数据库: 应用数据库目录
Q5: 如何备份和恢复数据?
A: 可以将数据导出为文件,或使用云备份服务。
扩展阅读
下一步
完成数据存储学习后,建议继续学习:
- 生命周期管理 - 学习页面和组件生命周期