HarmonyOS 5.0.0 或以上:文件与数据库混合存储策略(大字段写文件 + 元数据入 SQLite)
📌 场景介绍
对于以下情况,不建议将大内容直接存入 SQLite:
-
大体积字段:图片、音频、Base64 文件
-
高频读写场景(避免数据库膨胀)
-
文件下载缓存、语音留言、本地日志
推荐方案:
内容写入文件系统,元信息写入数据库
如:路径、时间戳、标签、文件名、类型等
🧱 页面结构
/entry/src/main/ets
└── pages/
└── MixedStorageDemo.ets // 文件+数据库混合存储页面
🧩 MixedStorageDemo.ets 示例页面
import fs from '@ohos.file.fs'
import relationalStore from '@ohos.data.relationalStore'
@Entry
@Component
struct MixedStorageDemo {
@State logs: Array<{ id: number, file: string, title: string }> = []
private db: relationalStore.RdbStore | undefined
private dir: string = '/data/storage/el2/base/files/logs'
private fileIndex: number = 0
aboutToAppear() {
this.init()
}
private async init() {
// 创建目录
if (!await fs.access(this.dir)) {
await fs.mkdir(this.dir)
}
// 初始化数据库
const context = getContext(this)
this.db = await relationalStore.getRdbStore(context, {
name: 'logmeta.db',
securityLevel: relationalStore.SecurityLevel.S1
}, 1, {
onCreate: async (rdb) => {
await rdb.executeSql(`CREATE TABLE IF NOT EXISTS log_meta (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT,
file TEXT
)`)
}
})
this.queryLogs()
}
private async writeLogAndInsertMeta() {
const content = `本地日志内容-${new Date().toLocaleString()}`
const filePath = `${this.dir}/log_${this.fileIndex++}.txt`
const file = await fs.open(filePath, fs.OpenMode.CREATE | fs.OpenMode.WRITE_ONLY | fs.OpenMode.TRUNC)
await fs.write(file.fd, new TextEncoder().encode(content))
await fs.close(file.fd)
await this.db?.insert('log_meta', { title: `日志 ${this.fileIndex}`, file: filePath })
this.queryLogs()
}
private async queryLogs() {
const resultSet = await this.db?.querySql('SELECT * FROM log_meta ORDER BY id DESC')
const list: Array<{ id: number, file: string, title: string }> = []
while (resultSet?.goToNextRow()) {
list.push({
id: resultSet.getInteger(0),
title: resultSet.getString(1),
file: resultSet.getString(2)
})
}
resultSet?.close()
this.logs = list
}
private async readFileContent(path: string): Promise<string> {
try {
const stat = await fs.stat(path)
const file = await fs.open(path, fs.OpenMode.READ_ONLY)
const buf = new Uint8Array(stat.size)
await fs.read(file.fd, buf)
await fs.close(file.fd)
return new TextDecoder().decode(buf)
} catch {
return '[文件读取失败]'
}
}
build() {
Column() {
Text("🧬 混合存储策略:文件+数据库").fontSize(22).margin(20)
Button("写入一条日志").onClick(() => this.writeLogAndInsertMeta()).margin(10)
ForEach(this.logs, (log) => {
Column()
.width('100%')
.padding(10)
.margin({ top: 10 })
.backgroundColor('#f7f7f7')
.borderRadius(6) {
Text(`📝 ${log.title}`).fontSize(16).fontWeight(FontWeight.Medium)
Text(`📂 ${log.file}`).fontSize(12).fontColor('#888')
Button("查看内容").onClick(async () => {
const content = await this.readFileContent(log.file)
this.logs = this.logs.map(l => l.id === log.id ? { ...l, content } : l)
}).fontSize(14).margin({ top: 6 })
If(log.content, () => {
Text(log.content!).fontSize(14).fontColor('#333').margin({ top: 6 })
})
}
})
}
.padding(20)
.height('100%')
.scrollable(true)
}
}
✅ 效果说明
-
每次点击按钮生成一条日志:内容写文件,元信息写数据库
-
文件名、路径、标题存入 SQLite
-
点击“查看内容”实时从文件读取原文展示
🔧 拓展建议
-
日志支持分级(debug/info/warn/error)写入
-
图片、视频等大文件走此策略存储路径即可
-
批量删除操作同时删除数据库与文件
-
可封装通用
ContentManager
管理大字段逻辑