ByteNoteByteNote

字节笔记本

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
大量二进制数据文件系统直接存储

注意事项

  1. 同步操作:示例使用 Sync 后缀的同步方法,简单但会阻塞 UI 线程。生产环境建议使用异步方法(readAsString()writeAsString())配合 async/await

  2. 错误处理:实际应用中需要添加 try-catch 处理文件操作异常。

  3. JSON 格式:确保写入的数据可 JSON 序列化,自定义对象需要实现 toJson() 方法。

  4. 版本更新:教程使用较旧版本语法(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'],
  );
}

相关资源

总结

本文介绍的 JSON 文件存储方案是 Flutter 本地持久化的基础实现,适合存储简单的结构化数据。通过 path_provider 获取安全目录,结合 dart:convert 进行 JSON 序列化,可以快速实现数据持久化功能。对于更复杂的需求,建议考虑 SQLite 或 Hive 等专门的数据库方案。

分享: