👋

【Flutter】日記アプリのDBデータのエクスポート方法

2025/02/24に公開

日記アプリの DB データのエクスポート方法

現在私は個人開発で日記アプリを作成しており、データのバックアップ方法に悩んでいました。そのため、日記アプリのデータベースの内容をエクスポートする際に、どのようなファイル形式が適切であるかを調査したので、メモとして残しておきます。

今回のサンプルコード

https://github.com/muranakar/file_export

データベースのエクスポート方法

まず、データベースのデータを 3 つの形式でエクスポートする方法があります。

  1. テキストファイル (.txt)
  2. CSV ファイル (.csv)
  3. データベースファイル (.db)

各ファイル形式の比較表

特徴 テキストファイル(.txt) CSV ファイル(.csv) データベースファイル(.db)
ファイルサイズ 大きい(整形テキストを含むため) 中程度 小さい(バイナリ形式)
可読性 ◎ 人間が直接読める ○ 表形式で理解しやすい × バイナリ形式で直接読めない
エディタでの開閉 ◎ メモ帳等で開ける ○ 表計算ソフトで開ける × 専用ツールが必要
互換性 ◎ どの OS でも読み書き可能 ◎ 多くのアプリで対応 △ SQLite 対応ツールが必要
データの完全性 × インデックス等は保持されない △ 表構造のみ保持 ◎ 全ての構造を保持
編集のしやすさ △ テキストエディタでの手動編集 ◎ Excel 等で簡単に編集可能 × 専用ツールが必要
大量データの処理 × 処理が遅い ○ 一括処理が可能 ◎ 効率的な処理が可能
アプリケーション連携 × 構造化されていない ◎ 多くのアプリが対応 ○ SQLite 対応アプリで利用可

テキストファイル(.txt) の特徴

  • データの目視確認が必要な場合
  • 簡易的なログ記録
  • 少量データの簡易バックアップ

CSV ファイル(.csv) の特徴

  • データの分析や加工が必要な場合
  • 他システムとのデータ連携
  • 一括データ処理
  • スプレッドシートでの編集
  • データの可視化

データベースファイル(.db) の特徴

  • アプリケーションの完全バックアップ
  • 大量データの効率的な管理
  • データベース構造の完全な保持が必要な場合

私の個人開発アプリ内での用途としては、

  • 日記を印刷して文字で確認する場合は、テキストファイル(.txt)
  • スプレットシートなどのツールで日記を確認したい場合、CSV ファイル(.csv)
  • 日記の DB データを完全にバックアップしたい場合、データベースファイル(.db)

このあたりの用途で使う可能性があると思いました。

実装方法

データベースの初期設定

最初に、データベースの設定とテーブルの作成を行います。

diary_database.dart

class DiaryDatabase {
  // シングルトンパターンでインスタンスを管理
  static final DiaryDatabase instance = DiaryDatabase._init();
  static Database? _database;

  DiaryDatabase._init();

  // データベースの取得
  Future<Database> get database async {
    if (_database != null) return _database!;
    _database = await _initDB('diary.db');
    return _database!;
  }

  // データベースの初期化
  Future<Database> _initDB(String filePath) async {
    final dbPath = await getDatabasesPath();
    final path = join(dbPath, filePath);

    return await openDatabase(
      path,
      version: 1,
      onCreate: _createDB,
    );
  }

  // テーブルの作成
  Future<void> _createDB(Database db, int version) async {
    await db.execute('''
    CREATE TABLE diaries (
      id INTEGER PRIMARY KEY AUTOINCREMENT,
      title TEXT,
      content TEXT,
      created_at TEXT
    )
    ''');
  }

テキストファイルへのエクスポート

人間が読みやすい形式でデータをエクスポートします。

diary_database.dart
  // テキストファイルへのエクスポート
  Future<String> exportToTxt() async {
    final db = await database;
    final diaries = await db.query('diaries');

    // アプリのドキュメントディレクトリを取得
    final docDir = await getApplicationDocumentsDirectory();
    final txtFile = File(join(docDir.path, 'diaries_${_formattedDate()}.txt'));

    // データの書き込み
    final buffer = StringBuffer();
    buffer.writeln('===== 日記リスト =====');

    for (var diary in diaries) {
      buffer.writeln('ID: ${diary['id']}');
      buffer.writeln('タイトル: ${diary['title']}');
      buffer.writeln('内容: ${diary['content']}');
      buffer.writeln('作成日時: ${diary['created_at']}');
      buffer.writeln('-------------------');
    }

    await txtFile.writeAsString(buffer.toString());
    return txtFile.path;
  }

CSV ファイルへのエクスポート

表計算ソフトで利用しやすい形式でエクスポートします。

diary_database.dart
  // CSVファイルへのエクスポート
  Future<String> exportToCsv() async {
    final db = await database;
    final diaries = await db.query('diaries');

    final docDir = await getApplicationDocumentsDirectory();
    final csvFile = File(join(docDir.path, 'diaries_${_formattedDate()}.csv'));

    // ヘッダー行の書き込み
    final buffer = StringBuffer();
    buffer.writeln('id,title,content,created_at');

    // データ行の書き込み
    for (var diary in diaries) {
      final values = [
        diary['id'],
        '"${diary['title']}"',  // カンマを含む可能性があるためダブルクォートで囲む
        '"${diary['content']}"',
        diary['created_at']
      ];
      buffer.writeln(values.join(','));
    }

    await csvFile.writeAsString(buffer.toString());
    return csvFile.path;
  }

データベースファイルのバックアップ

データベースファイル全体をコピーしてバックアップを作成します。

diary_database.dart
  // データベースファイルのバックアップ
  Future<String> exportDatabase() async {
    final db = await database;

    try {
      // データベースを一時的に閉じる
      if (_database != null && _database!.isOpen) {
        await _database!.close();
        _database = null;
      }

      // 元のデータベースファイルのパスを取得
      final dbPath = await getDatabasesPath();
      final dbFile = File(join(dbPath, 'diary.db'));

      // バックアップファイルのパスを設定
      final docDir = await getApplicationDocumentsDirectory();
      final backupPath =
          join(docDir.path, 'diary_backup_${_formattedDate()}.db');

      // ファイルをコピー
      await dbFile.copy(backupPath);
      return backupPath;
    } catch (e) {
      print('バックアップエラー: $e');
      rethrow;
    }
  }

db ファイルとして出力されるため、iOS のファイルアプリ上ではテキストが表示されません。db ファイル内のデータを確認するには、専用ツールが必要です。

使用方法

以下のように各エクスポート機能を呼び出すことができます。

main.dart
void main() async {
  // データベースのインスタンスを取得
  final db = DiaryDatabase.instance;

  // テキストファイルへエクスポート
  final txtPath = await db.exportToTxt();

  // CSVファイルへエクスポート
  final csvPath = await db.exportToCsv();

  // データベースファイルのバックアップ
  final dbPath = await db.exportDatabase();
}

まとめ

このように、Flutter アプリケーションでは複数の形式でデータをエクスポートすることができます。用途に応じて適切な形式を選択することで、効率的なデータバックアップと移行が可能になります。

Discussion