Flutter for OpenHarmony文件存储与数据库操作完全指南
本文系统介绍了Flutter for OpenHarmony中的数据存储方案,包括文件操作、SQLite数据库及性能优化技巧。主要内容涵盖:1)文件系统操作,如路径获取与文件读写封装;2)SQLite数据库从基础使用到高级特性;3)数据库迁移与性能优化策略;4)OpenHarmony平台存储适配要点。文章提供了完整的代码示例,解决了开发中常见的数据存储选择、性能瓶颈和安全问题,帮助开发者构建高效可
·
Flutter for OpenHarmony文件存储与数据库操作完全指南
前言

做应用开发,数据存储是绕不开的话题。简单的配置用SharedPreferences就够了,但复杂的业务数据就需要数据库。
Flutter for OpenHarmony 提供了多种数据持久化方案,但在实际开发中,很多开发者会遇到以下问题:
- SharedPreferences、SQLite、文件存储,该选哪个?
- 如何设计数据库表结构和迁移策略?
- 大量数据插入时性能太差怎么办?
- 如何避免SQL注入等安全问题?
- OpenHarmony平台存储路径有什么特殊之处?
这篇文章我将系统性地讲解Flutter for OpenHarmony中的数据存储方案,包括文件操作、SQLite数据库、以及性能优化技巧。
本文亮点:
- 完整的文件操作封装实现
- SQLite数据库从入门到精通
- 数据库迁移最佳实践
- 性能优化技巧(批量操作、索引优化)
- OpenHarmony平台存储适配要点
- 常见问题解决方案
一、文件系统操作

1.1 路径获取与管理
Flutter提供了path_provider插件来获取各种系统目录。
添加依赖:
dependencies:
path_provider: ^2.1.1
path: ^1.8.0
实现路径管理:
import 'package:path_provider/path_provider.dart';
import 'dart:io';
/// 路径管理器
class PathManager {
/// 获取临时目录
/// 用于缓存临时数据,系统可能随时清理
static Future<Directory> getTemporaryDirectory() async {
return await getTemporaryDirectory();
}
/// 获取应用文档目录
/// 用于存储用户数据,不会被系统清理
static Future<Directory> getAppDocumentDirectory() async {
return await getApplicationDocumentsDirectory();
}
/// 获取应用支持目录
/// 用于存储应用配置、缓存等
static Future<Directory> getAppSupportDirectory() async {
return await getApplicationSupportDirectory();
}
/// 获取外部存储目录(需要权限)
/// Android: /storage/emulated/0/Android/data/com.xxx.xxx/files
static Future<Directory?> getExternalStorageDirectory() async {
if (Platform.isAndroid || Platform.isIOS) {
return await getExternalStorageDirectory();
}
return null;
}
/// 创建自定义目录
static Future<Directory> createCustomDirectory(String dirName) async {
final appDocDir = await getAppDocumentDirectory();
final customDir = Directory('${appDocDir.path}/$dirName');
if (!await customDir.exists()) {
await customDir.create(recursive: true);
}
return customDir;
}
/// 获取所有可用路径信息
static Future<Map<String, String>> getAllPaths() async {
final paths = <String, String>{};
paths['临时目录'] = (await getTemporaryDirectory()).path;
paths['文档目录'] = (await getAppDocumentDirectory()).path;
paths['支持目录'] = (await getAppSupportDirectory()).path;
final externalDir = await getExternalStorageDirectory();
if (externalDir != null) {
paths['外部存储'] = externalDir.path;
}
return paths;
}
}
1.2 文件读写操作封装
import 'dart:io';
/// 文件操作工具类
class FileHelper {
/// 写入字符串到文件
static Future<void> writeString(String path, String content) async {
final file = File(path);
await file.writeAsString(content);
}
/// 读取字符串文件
static Future<String> readString(String path) async {
final file = File(path);
if (!await file.exists()) {
throw FileSystemException('文件不存在', path);
}
return await file.readAsString();
}
/// 写入字节数据
static Future<void> writeBytes(String path, List<int> bytes) async {
final file = File(path);
await file.writeAsBytes(bytes);
}
/// 读取字节数据
static Future<List<int>> readBytes(String path) async {
final file = File(path);
if (!await file.exists()) {
throw FileSystemException('文件不存在', path);
}
return await file.readAsBytes();
}
/// 检查文件是否存在
static Future<bool> exists(String path) async {
return await File(path).exists();
}
/// 删除文件
static Future<void> delete(String path) async {
final file = File(path);
if (await file.exists()) {
await file.delete();
}
}
/// 获取文件大小
static Future<int> getFileSize(String path) async {
final file = File(path);
if (!await file.exists()) {
return 0;
}
return await file.length();
}
/// 复制文件
static Future<void> copy(String sourcePath, String targetPath) async {
final sourceFile = File(sourcePath);
await sourceFile.copy(targetPath);
}
/// 重命名文件
static Future<void> rename(String oldPath, String newPath) async {
final file = File(oldPath);
await file.rename(newPath);
}
}
/// JSON文件操作
class JsonFileHelper {
/// 写入JSON对象到文件
static Future<void> writeJson(String path, Map<String, dynamic> data) async {
final jsonString = const JsonEncoder.withIndent(' ').convert(data);
await FileHelper.writeString(path, jsonString);
}
/// 从文件读取JSON对象
static Future<Map<String, dynamic>> readJson(String path) async {
final jsonString = await FileHelper.readString(path);
final jsonData = jsonDecode(jsonString) as Map<String, dynamic>;
return jsonData;
}
/// 写入JSON数组到文件
static Future<void> writeJsonList(String path, List<dynamic> data) async {
final jsonString = const JsonEncoder.withIndent(' ').convert(data);
await FileHelper.writeString(path, jsonString);
}
/// 从文件读取JSON数组
static Future<List<dynamic>> readJsonList(String path) async {
final jsonString = await FileHelper.readString(path);
final jsonData = jsonDecode(jsonString) as List<dynamic>;
return jsonData;
}
}
1.3 目录操作封装
/// 目录操作工具类
class DirectoryHelper {
/// 创建目录
static Future<void> createDirectory(String path) async {
final dir = Directory(path);
if (!await dir.exists()) {
await dir.create(recursive: true);
}
}
/// 列出目录下所有文件
static Future<List<FileSystemEntity>> listFiles(String path) async {
final dir = Directory(path);
if (!await dir.exists()) {
return [];
}
return dir.listSync();
}
/// 列出目录下所有文件(递归)
static Future<List<File>> listFilesRecursively(String path) async {
final dir = Directory(path);
if (!await dir.exists()) {
return [];
}
final files = <File>[];
await for (final entity in dir.list(recursive: true)) {
if (entity is File) {
files.add(entity);
}
}
return files;
}
/// 删除目录
static Future<void> deleteDirectory(String path) async {
final dir = Directory(path);
if (await dir.exists()) {
await dir.delete(recursive: true);
}
}
/// 获取目录大小
static Future<int> getDirectorySize(String path) async {
final files = await listFilesRecursively(path);
int totalSize = 0;
for (final file in files) {
totalSize += await file.length();
}
return totalSize;
}
/// 清空目录(删除目录下所有文件)
static Future<void> clearDirectory(String path) async {
final dir = Directory(path);
if (!await dir.exists()) {
return;
}
await for (final entity in dir.list()) {
if (entity is File) {
await entity.delete();
} else if (entity is Directory) {
await entity.delete(recursive: true);
}
}
}
}
二、SQLite数据库操作

2.1 数据库辅助类实现
添加依赖:
dependencies:
sqflite: ^2.3.0
path: ^1.8.0
实现数据库管理:
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
/// 数据库版本号
const int _databaseVersion = 1;
/// 数据库名称
const String _databaseName = 'app_database.db';
/// 数据库管理类
class DatabaseHelper {
// 单例模式
static final DatabaseHelper _instance = DatabaseHelper._internal();
factory DatabaseHelper() => _instance;
DatabaseHelper._internal();
static Database? _database;
/// 获取数据库实例
Future<Database> get database async {
if (_database != null) return _database!;
_database = await _initDatabase();
return _database!;
}
/// 初始化数据库
Future<Database> _initDatabase() async {
// 获取数据库路径
final dbPath = await getDatabasesPath();
final path = join(dbPath, _databaseName);
// 打开数据库,如果不存在则创建
return await openDatabase(
path,
version: _databaseVersion,
onCreate: _onCreate,
onUpgrade: _onUpgrade,
onConfigure: _onConfigure,
);
}
/// 数据库配置
static Future<void> _onConfigure(Database db) async {
// 启用外键约束
await db.execute('PRAGMA foreign_keys = ON');
}
/// 创建数据库表
Future<void> _onCreate(Database db, int version) async {
// 创建用户表
await db.execute('''
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL UNIQUE,
email TEXT NOT NULL UNIQUE,
password TEXT NOT NULL,
nickname TEXT,
avatar TEXT,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL
)
''');
// 创建待办事项表
await db.execute('''
CREATE TABLE todos (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
description TEXT,
is_completed INTEGER DEFAULT 0,
priority INTEGER DEFAULT 0,
due_date INTEGER,
user_id INTEGER NOT NULL,
created_at INTEGER NOT NULL,
updated_at INTEGER NOT NULL,
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
)
''');
// 创建索引
await _createIndexes(db);
}
/// 创建索引
static Future<void> _createIndexes(Database db) async {
// 用户表索引
await db.execute('CREATE INDEX idx_users_username ON users(username)');
await db.execute('CREATE INDEX idx_users_email ON users(email)');
// 待办事项表索引
await db.execute('CREATE INDEX idx_todos_user_id ON todos(user_id)');
await db.execute('CREATE INDEX idx_todos_due_date ON todos(due_date)');
await db.execute('CREATE INDEX idx_todos_is_completed ON todos(is_completed)');
}
/// 数据库升级
Future<void> _onUpgrade(Database db, int oldVersion, int newVersion) async {
if (oldVersion < 2) {
// 版本1到版本2的升级
await db.execute('ALTER TABLE users ADD COLUMN phone TEXT');
await db.execute('ALTER TABLE users ADD COLUMN gender INTEGER DEFAULT 0');
}
if (oldVersion < 3) {
// 版本2到版本3的升级
await db.execute('ALTER TABLE todos ADD COLUMN tags TEXT');
}
// 更多版本升级...
}
/// 关闭数据库
Future<void> close() async {
final db = await database;
await db.close();
_database = null;
}
}
2.2 数据模型定义
/// 用户模型
class User {
final int? id;
final String username;
final String email;
final String password;
final String? nickname;
final String? avatar;
final DateTime createdAt;
final DateTime updatedAt;
User({
this.id,
required this.username,
required this.email,
required this.password,
this.nickname,
this.avatar,
required this.createdAt,
required this.updatedAt,
});
/// 从Map创建
factory User.fromMap(Map<String, dynamic> map) {
return User(
id: map['id'] as int?,
username: map['username'] as String,
email: map['email'] as String,
password: map['password'] as String,
nickname: map['nickname'] as String?,
avatar: map['avatar'] as String?,
createdAt: DateTime.fromMillisecondsSinceEpoch(map['created_at'] as int),
updatedAt: DateTime.fromMillisecondsSinceEpoch(map['updated_at'] as int),
);
}
/// 转换为Map
Map<String, dynamic> toMap() {
return {
'id': id,
'username': username,
'email': email,
'password': password,
'nickname': nickname,
'avatar': avatar,
'created_at': createdAt.millisecondsSinceEpoch,
'updated_at': updatedAt.millisecondsSinceEpoch,
};
}
/// 复制并修改部分字段
User copyWith({
int? id,
String? username,
String? email,
String? password,
String? nickname,
String? avatar,
DateTime? createdAt,
DateTime? updatedAt,
}) {
return User(
id: id ?? this.id,
username: username ?? this.username,
email: email ?? this.email,
password: password ?? this.password,
nickname: nickname ?? this.nickname,
avatar: avatar ?? this.avatar,
createdAt: createdAt ?? this.createdAt,
updatedAt: updatedAt ?? this.updatedAt,
);
}
}
/// 待办事项模型
class Todo {
final int? id;
final String title;
final String? description;
final bool isCompleted;
final int priority;
final DateTime? dueDate;
final int userId;
final DateTime createdAt;
final DateTime updatedAt;
final String? tags;
Todo({
this.id,
required this.title,
this.description,
this.isCompleted = false,
this.priority = 0,
this.dueDate,
required this.userId,
required this.createdAt,
required this.updatedAt,
this.tags,
});
/// 从Map创建
factory Todo.fromMap(Map<String, dynamic> map) {
return Todo(
id: map['id'] as int?,
title: map['title'] as String,
description: map['description'] as String?,
isCompleted: (map['is_completed'] as int) == 1,
priority: map['priority'] as int? ?? 0,
dueDate: map['due_date'] != null
? DateTime.fromMillisecondsSinceEpoch(map['due_date'] as int)
: null,
userId: map['user_id'] as int,
createdAt: DateTime.fromMillisecondsSinceEpoch(map['created_at'] as int),
updatedAt: DateTime.fromMillisecondsSinceEpoch(map['updated_at'] as int),
tags: map['tags'] as String?,
);
}
/// 转换为Map
Map<String, dynamic> toMap() {
return {
'id': id,
'title': title,
'description': description,
'is_completed': isCompleted ? 1 : 0,
'priority': priority,
'due_date': dueDate?.millisecondsSinceEpoch,
'user_id': userId,
'created_at': createdAt.millisecondsSinceEpoch,
'updated_at': updatedAt.millisecondsSinceEpoch,
'tags': tags,
};
}
}
2.3 DAO层实现
/// 用户数据访问对象
class UserDao {
final DatabaseHelper _dbHelper = DatabaseHelper();
/// 插入用户
Future<int> insert(User user) async {
final db = await _dbHelper.database;
return await db.insert('users', user.toMap());
}
/// 批量插入用户
Future<void> insertBatch(List<User> users) async {
final db = await _dbHelper.database;
final batch = db.batch();
for (final user in users) {
batch.insert('users', user.toMap());
}
await batch.commit(noResult: true);
}
/// 根据ID查询用户
Future<User?> queryById(int id) async {
final db = await _dbHelper.database;
final List<Map<String, dynamic>> maps = await db.query(
'users',
where: 'id = ?',
whereArgs: [id],
);
if (maps.isEmpty) return null;
return User.fromMap(maps.first);
}
/// 根据用户名查询用户
Future<User?> queryByUsername(String username) async {
final db = await _dbHelper.database;
final List<Map<String, dynamic>> maps = await db.query(
'users',
where: 'username = ?',
whereArgs: [username],
);
if (maps.isEmpty) return null;
return User.fromMap(maps.first);
}
/// 查询所有用户
Future<List<User>> queryAll() async {
final db = await _dbHelper.database;
final List<Map<String, dynamic>> maps = await db.query('users');
return maps.map((map) => User.fromMap(map)).toList();
}
/// 分页查询用户
Future<List<User>> queryByPage(int page, int pageSize) async {
final db = await _dbHelper.database;
final offset = (page - 1) * pageSize;
final List<Map<String, dynamic>> maps = await db.query(
'users',
limit: pageSize,
offset: offset,
orderBy: 'created_at DESC',
);
return maps.map((map) => User.fromMap(map)).toList();
}
/// 更新用户
Future<int> update(User user) async {
final db = await _dbHelper.database;
return await db.update(
'users',
user.toMap(),
where: 'id = ?',
whereArgs: [user.id],
);
}
/// 删除用户
Future<int> delete(int id) async {
final db = await _dbHelper.database;
return await db.delete(
'users',
where: 'id = ?',
whereArgs: [id],
);
}
/// 获取用户总数
Future<int> getCount() async {
final db = await _dbHelper.database;
final result = await db.rawQuery('SELECT COUNT(*) as count FROM users');
return Sqflite.firstIntValue(result) ?? 0;
}
}
/// 待办事项数据访问对象
class TodoDao {
final DatabaseHelper _dbHelper = DatabaseHelper();
/// 插入待办事项
Future<int> insert(Todo todo) async {
final db = await _dbHelper.database;
return await db.insert('todos', todo.toMap());
}
/// 根据ID查询待办事项
Future<Todo?> queryById(int id) async {
final db = await _dbHelper.database;
final List<Map<String, dynamic>> maps = await db.query(
'todos',
where: 'id = ?',
whereArgs: [id],
);
if (maps.isEmpty) return null;
return Todo.fromMap(maps.first);
}
/// 查询用户的所有待办事项
Future<List<Todo>> queryByUserId(int userId) async {
final db = await _dbHelper.database;
final List<Map<String, dynamic>> maps = await db.query(
'todos',
where: 'user_id = ?',
whereArgs: [userId],
orderBy: 'created_at DESC',
);
return maps.map((map) => Todo.fromMap(map)).toList();
}
/// 查询未完成的待办事项
Future<List<Todo>> queryIncompleteTodos(int userId) async {
final db = await _dbHelper.database;
final List<Map<String, dynamic>> maps = await db.query(
'todos',
where: 'user_id = ? AND is_completed = ?',
whereArgs: [userId, 0],
orderBy: 'due_date ASC',
);
return maps.map((map) => Todo.fromMap(map)).toList();
}
/// 更新待办事项
Future<int> update(Todo todo) async {
final db = await _dbHelper.database;
return await db.update(
'todos',
todo.toMap(),
where: 'id = ?',
whereArgs: [todo.id],
);
}
/// 标记待办事项为完成
Future<int> markAsComplete(int id) async {
final db = await _dbHelper.database;
return await db.update(
'todos',
{
'is_completed': 1,
'updated_at': DateTime.now().millisecondsSinceEpoch,
},
where: 'id = ?',
whereArgs: [id],
);
}
/// 删除待办事项
Future<int> delete(int id) async {
final db = await _dbHelper.database;
return await db.delete(
'todos',
where: 'id = ?',
whereArgs: [id],
);
}
/// 删除用户的所有待办事项
Future<int> deleteByUserId(int userId) async {
final db = await _dbHelper.database;
return await db.delete(
'todos',
where: 'user_id = ?',
whereArgs: [userId],
);
}
}
三、数据库事务与性能优化
3.1 事务处理
/// 事务管理器
class TransactionManager {
final DatabaseHelper _dbHelper = DatabaseHelper();
/// 转账示例 - 使用事务保证数据一致性
Future<void> transferMoney(
int fromUserId,
int toUserId,
double amount,
) async {
final db = await _dbHelper.database;
await db.transaction((txn) async {
// 1. 扣除转出用户余额
await txn.update(
'users',
{'balance': -amount, 'updated_at': DateTime.now().millisecondsSinceEpoch},
where: 'id = ?',
whereArgs: [fromUserId],
);
// 2. 增加转入用户余额
await txn.update(
'users',
{'balance': amount, 'updated_at': DateTime.now().millisecondsSinceEpoch},
where: 'id = ?',
whereArgs: [toUserId],
);
});
}
/// 批量插入 - 使用事务提升性能
Future<void> batchInsert(List<User> users) async {
final db = await _dbHelper.database;
await db.transaction((txn) async {
final batch = txn.batch();
for (final user in users) {
batch.insert('users', user.toMap());
}
await batch.commit(noResult: true);
});
}
/// 带异常处理的事务
Future<T> transaction<T>(
Future<T> Function(Transaction) action,
) async {
final db = await _dbHelper.database;
return await db.transaction((txn) async {
try {
return await action(txn);
} catch (e) {
// 记录错误日志
debugPrint('事务执行失败: $e');
rethrow;
}
});
}
}
3.2 性能优化技巧
/// 数据库性能优化工具
class DatabaseOptimizer {
final DatabaseHelper _dbHelper = DatabaseHelper();
/// 批量操作优化
Future<void> optimizedBatchInsert(List<Todo> todos) async {
final db = await _dbHelper.database;
// 使用批量插入而非逐条插入
await db.transaction((txn) async {
final batch = txn.batch();
for (final todo in todos) {
batch.insert('todos', todo.toMap());
}
// noResult: true 提升性能(不返回结果)
await batch.commit(noResult: true);
});
}
/// 分页查询优化
Future<List<Todo>> optimizedPaginatedQuery(
int page,
int pageSize,
) async {
final db = await _dbHelper.database;
final offset = (page - 1) * pageSize;
// 只查询需要的字段
final List<Map<String, dynamic>> maps = await db.query(
'todos',
columns: ['id', 'title', 'is_completed', 'due_date'],
limit: pageSize,
offset: offset,
orderBy: 'created_at DESC',
);
return maps.map((map) => Todo.fromMap(map)).toList();
}
/// 使用索引优化查询
Future<List<Todo>> indexedQuery(int userId) async {
final db = await _dbHelper.database;
// 确保user_id字段有索引
final List<Map<String, dynamic>> maps = await db.query(
'todos',
where: 'user_id = ?',
whereArgs: [userId],
// 利用索引排序
orderBy: 'due_date ASC',
);
return maps.map((map) => Todo.fromMap(map)).toList();
}
/// 清理数据表
Future<void> vacuumDatabase() async {
final db = await _dbHelper.database;
await db.execute('VACUUM');
}
/// 分析表并更新统计信息
Future<void> analyzeTable(String tableName) async {
final db = await _dbHelper.database;
await db.execute('ANALYZE $tableName');
}
}
总结
本文系统性地讲解了Flutter for OpenHarmony中的文件存储和数据库操作,从基础API到性能优化。
核心要点回顾
| 技术点 | 关键内容 | 注意事项 |
|---|---|---|
| 文件存储 | path_provider、File操作 | 注意路径权限 |
| SQLite | 单例模式、DAO层 | 防止内存泄漏 |
| 事务处理 | 保证数据一致性 | 及时回滚 |
| 性能优化 | 批量操作、索引 | 避免N+1查询 |
| 数据迁移 | 版本管理 | 向后兼容 |
最佳实践建议
- 使用单例模式管理数据库
- DAO层封装数据访问
- 复杂查询使用事务
- 批量操作提升性能
- 合理使用索引
- 做好数据库版本管理
相关资源:
欢迎加入开源鸿蒙跨平台社区: 开源鸿蒙跨平台开发者社区
如果这篇文章对你有帮助,请点赞、收藏、分享,让更多开发者看到!
写于2025年 | Flutter for OpenHarmony系列教程
更多推荐



所有评论(0)