パスを正しく結合する(Join)

Recipe ID: fs-021

OS ごとのパス区切り文字(Windows の \ や macOS/Linux の /)の違いを意識せずに、複数のパスセグメントを安全に結合する方法を解説します。
文字列連結でパスを作成すると、異なる OS でバグの原因になるため、必ず join 関数を使用してください。

使用方法

@tauri-apps/api/path から join をインポートして使用します。

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

// "documents" と "my_file.txt" を結合
const fullPath = await join('documents', 'my_file.txt');

OS に応じて自動的に適切な区切り文字が使用されます。

OS結果の例
Windowsdocuments\my_file.txt
macOS/Linuxdocuments/my_file.txt

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

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

ディレクトリパスとファイル名を結合する

ベースディレクトリのパス(Promise で取得したものなど)とファイル名を結合する一般的なパターンです。

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

async function getFilePath() {
    try {
        const home = await homeDir();
        // homeディレクトリ + 'Downloads' + 'image.png'
        const filePath = await join(home, 'Downloads', 'image.png');
        
        console.log(filePath);
        // Windows: C:\Users\Name\Downloads\image.png
        // macOS: /Users/Name/Downloads/image.png
        return filePath;
    } catch (err) {
        console.error(err);
    }
}

複数のセグメントを一度に結合する

join 関数は可変長引数を受け取るため、何階層でも一度に連結できます。

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

async function getDeepPath() {
    const dataDir = await appLocalDataDir();
    
    // dataDir/logs/2023/12/error.log のようなパスを作成
    const logPath = await join(dataDir, 'logs', '2023', '12', 'error.log');
    
    console.log('Log file path:', logPath);
}

絶対パスの作成(resolve との違い)

join は単純な結合を行いますが、Tauri の API は基本的に結合後のパスの正規化も行います。
.. (親ディレクトリ) を含むパスの解決が必要な場合も joinnormalize が役立ちます。

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

async function normalizePath() {
    // 'folder/sub/../file.txt' -> 'folder/file.txt' のように正規化される
    const normalized = await join('folder', 'sub', '..', 'file.txt');
    console.log(normalized);
}

補足

  • join: フロントエンドでは非同期関数ですが、パス文字列の操作のみを行い、ファイルシステムへのアクセスは(基本的には)行いません。
  • 区切り文字: join を使用することで、OS(Windows かそれ以外か)に適した区切り文字が自動的に適用されます。