字
字节笔记本
2026年2月18日
Flutter JSON 本地存储完全指南
API中转
¥120
本文介绍 Flutter 本地 JSON 文件存储的完整实现方案,使用 path_provider 插件访问应用文档目录,实现简单的键值对数据持久化存储。
教程简介
这是 Flutter Tutorials Handbook 系列的第 13 章,讲解如何在 Flutter 应用中实现本地 JSON 文件的读写操作。该方案适用于需要存储简单结构化数据的场景,如用户配置、应用状态缓存等。
核心知识点
1. 依赖包
yaml
dependencies:
flutter:
sdk: flutter
path_provider: "^0.4.0"path_provider 插件用于获取应用目录路径:
getTemporaryDirectory()- 临时存储目录(可能被系统清理)getApplicationDocumentsDirectory()- 应用文档目录(持久化存储)
2. JSON 处理
需要导入 dart:convert 库:
dart
import 'dart:convert';
// JSON 编码(Map → JSON 字符串)
String jsonString = json.encode(mapData);
// JSON 解码(JSON 字符串 → Map)
Map<String, dynamic> data = json.decode(jsonString);3. 文件操作
Flutter 使用 dart:io 库进行文件操作:
dart
import 'dart:io';
// 创建文件
File file = File(filePath);
file.createSync();
// 写入内容
file.writeAsStringSync(content);
// 读取内容
String content = file.readAsStringSync();
// 检查文件是否存在
bool exists = file.existsSync();完整代码实现
main.dart
dart
import 'package:flutter/material.dart';
import 'dart:io';
import 'dart:convert';
import 'package:path_provider/path_provider.dart';
void main() {
runApp(MaterialApp(
home: Home(),
));
}
class Home extends StatefulWidget {
@override
State createState() => HomeState();
}
class HomeState extends State<Home> {
// 输入控制器
TextEditingController keyInputController = TextEditingController();
TextEditingController valueInputController = TextEditingController();
// 文件相关
File jsonFile;
Directory dir;
String fileName = "myJSONFile.json";
bool fileExists = false;
Map<String, String> fileContent;
@override
void initState() {
super.initState();
// 获取应用文档目录并初始化文件
getApplicationDocumentsDirectory().then((Directory directory) {
dir = directory;
jsonFile = File("${dir.path}/$fileName");
fileExists = jsonFile.existsSync();
if (fileExists) {
setState(() {
fileContent = json.decode(jsonFile.readAsStringSync());
});
}
});
}
@override
void dispose() {
keyInputController.dispose();
valueInputController.dispose();
super.dispose();
}
// 创建新文件
void createFile(Map<String, String> content, Directory dir, String fileName) {
print("Creating file!");
File file = File("${dir.path}/$fileName");
file.createSync();
fileExists = true;
file.writeAsStringSync(json.encode(content));
}
// 写入数据到文件
void writeToFile(String key, String value) {
print("Writing to file!");
Map<String, String> content = {key: value};
if (fileExists) {
print("File exists");
Map<String, String> jsonFileContent =
json.decode(jsonFile.readAsStringSync());
jsonFileContent.addAll(content);
jsonFile.writeAsStringSync(json.encode(jsonFileContent));
} else {
print("File does not exist!");
createFile(content, dir, fileName);
}
setState(() {
fileContent = json.decode(jsonFile.readAsStringSync());
});
print(fileContent);
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("JSON Tutorial"),
),
body: Column(
children: <Widget>[
Padding(padding: EdgeInsets.only(top: 10.0)),
Text(
"File content: ",
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(fileContent.toString()),
Padding(padding: EdgeInsets.only(top: 10.0)),
Text("Add to JSON file: "),
TextField(controller: keyInputController),
TextField(controller: valueInputController),
Padding(padding: EdgeInsets.only(top: 20.0)),
ElevatedButton(
child: Text("Add key, value pair"),
onPressed: () => writeToFile(
keyInputController.text,
valueInputController.text,
),
),
],
),
);
}
}关键代码解析
1. 文件路径构建
dart
getApplicationDocumentsDirectory().then((Directory directory) {
dir = directory;
jsonFile = File("${dir.path}/$fileName");
// ...
});使用 getApplicationDocumentsDirectory() 获取应用私有目录,确保数据在应用生命周期内持久保存。
2. 数据读写流程
dart
// 读取流程
fileExists = jsonFile.existsSync();
if (fileExists) {
fileContent = json.decode(jsonFile.readAsStringSync());
}
// 写入流程
Map<String, String> content = {key: value};
if (fileExists) {
// 追加模式:读取 → 合并 → 写入
Map<String, String> existing = json.decode(jsonFile.readAsStringSync());
existing.addAll(content);
jsonFile.writeAsStringSync(json.encode(existing));
} else {
// 创建新文件
createFile(content, dir, fileName);
}3. 状态更新
每次写入后调用 setState() 更新 UI,实时显示文件内容:
dart
setState(() {
fileContent = json.decode(jsonFile.readAsStringSync());
});使用场景
| 场景 | 推荐方案 |
|---|---|
| 简单键值对(配置项) | shared_preferences |
| 结构化 JSON 数据 | 本文方案(JSON 文件存储) |
| 复杂关系型数据 | SQLite |
| 大量二进制数据 | 文件系统直接存储 |
注意事项
-
同步操作:示例使用
Sync后缀的同步方法,简单但会阻塞 UI 线程。生产环境建议使用异步方法(readAsString()、writeAsString())配合async/await。 -
错误处理:实际应用中需要添加 try-catch 处理文件操作异常。
-
JSON 格式:确保写入的数据可 JSON 序列化,自定义对象需要实现
toJson()方法。 -
版本更新:教程使用较旧版本语法(
new关键字、JSON大写),现代 Dart 推荐:- 省略
new关键字 - 使用小写
json替代JSON
- 省略
扩展改进
异步版本
dart
Future<void> writeToFileAsync(String key, String value) async {
try {
Map<String, String> content = {key: value};
if (await jsonFile.exists()) {
String existing = await jsonFile.readAsString();
Map<String, dynamic> data = json.decode(existing);
data.addAll(content);
await jsonFile.writeAsString(json.encode(data));
} else {
await jsonFile.create();
await jsonFile.writeAsString(json.encode(content));
}
setState(() async {
fileContent = json.decode(await jsonFile.readAsString());
});
} catch (e) {
print("Error: $e");
}
}数据模型封装
dart
class UserSettings {
String username;
bool isDarkMode;
int fontSize;
UserSettings({this.username, this.isDarkMode, this.fontSize});
Map<String, dynamic> toJson() => {
'username': username,
'isDarkMode': isDarkMode,
'fontSize': fontSize,
};
factory UserSettings.fromJson(Map<String, dynamic> json) => UserSettings(
username: json['username'],
isDarkMode: json['isDarkMode'],
fontSize: json['fontSize'],
);
}相关资源
- 教程来源:Flutter Tutorials Handbook - JSON Storage
- path_provider 插件:pub.dev/packages/path_provider
- Dart JSON 文档:dart.dev/guides/libraries/library-tour#dartconvert
总结
本文介绍的 JSON 文件存储方案是 Flutter 本地持久化的基础实现,适合存储简单的结构化数据。通过 path_provider 获取安全目录,结合 dart:convert 进行 JSON 序列化,可以快速实现数据持久化功能。对于更复杂的需求,建议考虑 SQLite 或 Hive 等专门的数据库方案。
分享: