アプリ専用のデータ保存フォルダパスを取得する

Recipe ID: fs-017

Windows, macOS, Linux の各 OS ごとに適切な「アプリ専用のデータ保存フォルダ」や「設定ファイル保存フォルダ」のパスを取得する方法を解説します。
Tauri では @tauri-apps/api/path モジュールを使用することで、OS の違いを意識せずに適切なパスを取得できます。

前提条件

この機能を使用するには、@tauri-apps/api パッケージが必要です(通常は初期設定でインストールされています)。
また、ファイル操作を行うため、@tauri-apps/plugin-fs プラグインのインストールが必要です。

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

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

npm run tauri add fs

2. Permissions (権限) の設定

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

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

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

使用方法

@tauri-apps/api/path から必要な関数をインポートして使用します。
取得できるパスはすべて Promise<string> を返す非同期関数です。

主なパス取得関数

関数名説明Windows の例 (※)macOS の例 (※)
appLocalDataDir()アプリ専用データ
キャッシュやDBなど、同期不要なデータ
~/AppData/Local/{bundleId}~/Library/Application Support/{bundleId}
appConfigDir()設定ファイル
ユーザー設定など
~/AppData/Roaming/{bundleId}~/Library/Application Support/{bundleId}
appLogDir()ログファイル~/AppData/Local/{bundleId}/logs~/Library/Logs/{bundleId}
resourceDir()リソース
アプリにバンドルされたファイル
インストール先によるApp Bundle 内
join()パスの結合\ 区切り/ 区切り
(※) {bundleId}tauri.conf.jsonidentifier です。
(※) Linux では XDG Base Directory Specification に従います(例: ~/.local/share/{bundleId})。

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

@tauri-apps/api/pathappLocalDataDir 関数を使用します。

データ保存用ディレクトリのパスを取得する

import { appLocalDataDir, join } from '@tauri-apps/api/path';

async function getDataPath() {
  try {
    // アプリ専用のデータディレクトリパスを取得
    const dataDir = await appLocalDataDir();
    console.log('Data Directory:', dataDir);

    // その配下のファイルパスを作成 (例: data.json)
    // join を使うことで OS ごとのパス区切り文字 (\ または /) を自動処理します
    const filePath = await join(dataDir, 'data.json');
    console.log('File Path:', filePath);
    
    return filePath;
  } catch (err) {
    console.error('Failed to resolve path:', err);
  }
}

設定ディレクトリとリソースディレクトリ

import { appConfigDir, resourceDir } from '@tauri-apps/api/path';

async function showPaths() {
    const configPath = await appConfigDir();
    const resourcePath = await resourceDir();

    console.log(`Config should be saved at: ${configPath}`);
    console.log(`Bundled resources are at: ${resourcePath}`);
}

ファイル操作との組み合わせ(実践例)

取得したパスを使ってフォルダを作成したり、ファイルを読み書きする例です。
(※ fs プラグインのインストールと権限設定が必要です)

import { appLocalDataDir, join } from '@tauri-apps/api/path';
import { mkdir, writeTextFile, exists } from '@tauri-apps/plugin-fs';

async function saveUserData(data: any) {
    // 1. パスを取得
    const baseDir = await appLocalDataDir();
    const filePath = await join(baseDir, 'user_settings.json');

    // 2. ディレクトリが存在するか確認し、なければ作成
    if (!(await exists(baseDir))) {
        await mkdir(baseDir, { recursive: true });
    }

    // 3. ファイルを保存
    await writeTextFile(filePath, JSON.stringify(data));
    console.log('Saved to:', filePath);
}

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

Rust では start-tauri で生成される AppHandle からパスを取得できます。

AppHandle からパスを取得

Tauri v2 では app_handle.path() を通じてパスリゾルバにアクセスします。

use tauri::Manager; // .path() を使うために必要

#[tauri::command]
fn get_app_local_data_dir(app: tauri::AppHandle) -> Result<String, String> {
    // Result<PathBuf, ...> を返す
    let path_buf = app.path().app_local_data_dir().map_err(|e| e.to_string())?;
    
    // PathBuf -> String 変換
    Ok(path_buf.to_string_lossy().into_owned())
}

パスの結合とディレクトリ作成

use tauri::Manager;
use std::fs;

#[tauri::command]
fn setup_data_file(app: tauri::AppHandle) -> Result<String, String> {
    let data_dir = app.path().app_local_data_dir().map_err(|e| e.to_string())?;

    // ディレクトリが存在しない場合は作成
    if !data_dir.exists() {
        fs::create_dir_all(&data_dir).map_err(|e| e.to_string())?;
    }

    // パスの結合 (join)
    let file_path = data_dir.join("data.json");
    
    Ok(file_path.to_string_lossy().into_owned())
}

補足

  • 非同期: フロントエンドの path 関数は非同期ですが、Rust 側ではブロッキング的にパスを返します(I/O は発生しないため高速です)。
  • path:default: フロントエンドからパスを取得するには、Capabilities で path:default を許可する必要があります。