ファイルの末尾にデータを追記する

Recipe ID: fs-005

既存のファイル内容を消さずに、末尾に新しいデータを追加する方法を紹介します。
これはログファイルの記録や、既存のリストへのデータの追加などに非常に便利です。

前提条件

このレシピを使用するには、@tauri-apps/plugin-fs プラグインが必要です。

1. プラグインのインストール

プロジェクトのルートディレクトリで以下のコマンドを実行してプラグインを追加します。

npm run tauri add fs

2. Permissions (権限) の設定

src-tauri/capabilities/default.json に以下の権限を追加します。

{
  "permissions": [
    ...,
    {
      "identifier": "fs:allow-write-text-file",
      "allow": [{ "path": "$APPLOCALDATA/**" }]
    },
    {
      "identifier": "fs:allow-write-file",
      "allow": [{ "path": "$APPLOCALDATA/**" }]
    }
  ]
}

※ 上記の例では $APPLOCALDATABaseDirectory.AppLocalData)配下の書き込み(追記)を許可しています。アクセスするディレクトリに応じて、パス変数を指定してください。スコープが設定されていないディレクトリにはアクセスできません。

1. フロントエンドから作成する (TypeScript)

@tauri-apps/plugin-fswriteTextFilewriteFile 関数で append: true を指定します。

テキストの追記(ログ出力)

writeTextFile 関数の第3引数オプションで { append: true } を指定することで、上書きではなく追記モードになります。

import { writeTextFile, BaseDirectory } from '@tauri-apps/plugin-fs';

async function appendLog(message: string) {
  const logLine = `[${new Date().toISOString()}] ${message}\n`;
  
  try {
    await writeTextFile('app.log', logLine, {
      baseDir: BaseDirectory.AppLocalData,
      append: true, // このオプションが重要です
    });
    console.log('ログを追記しました');
  } catch (err) {
    console.error('ログ追記エラー:', err);
  }
}

// 使用例
// await appendLog('アプリケーションが起動しました');
// await appendLog('ユーザーがログインしました');

バイナリデータの追記

writeFile でも同様に append: true が使用できます。

import { writeFile, BaseDirectory } from '@tauri-apps/plugin-fs';

async function appendBinaryData(newData: Uint8Array) {
  try {
    await writeFile('data.bin', newData, {
      baseDir: BaseDirectory.AppLocalData,
      append: true,
    });
  } catch (err) {
    console.error('バイナリ追記エラー:', err);
  }
}

2. バックエンドから作成する (Rust)

Rust の std::fs::OpenOptions を使用して追記モードでファイルを開きます。

テキストの追記

use std::fs::OpenOptions;
use std::io::Write;

#[tauri::command]
fn append_log_line(path: String, line: String) -> Result<(), String> {
    let mut file = OpenOptions::new()
        .create(true) // ファイルがない場合は作成
        .append(true) // 追記モード
        .open(path)
        .map_err(|e| e.to_string())?;

    writeln!(file, "{}", line).map_err(|e| e.to_string())
}

バイナリの追記

use std::fs::OpenOptions;
use std::io::Write;

#[tauri::command]
fn append_bytes(path: String, data: Vec<u8>) -> Result<(), String> {
    let mut file = OpenOptions::new()
        .create(true)
        .append(true)
        .open(path)
        .map_err(|e| e.to_string())?;

    file.write_all(&data).map_err(|e| e.to_string())
}

補足

  • append: true: このオプションを指定すると、ファイルポインタが末尾に移動してから書き込みが行われます。
  • ファイルの自動作成: OpenOptions::create(true) (Rust) や append: true (JS) を指定すると、ファイルが存在しない場合に新規作成します。
  • 改行コード: Rust の writeln! マクロは自動的に改行(OS依存の場合は \n or \r\n)を追加しますが、write! は追加しません。JS の writeTextFile も自動的には追加しません。
  • 同期・非同期: JS 側は Promise ベースですが、Rust 例の std::fs は同期処理です。