Qtのパス変換はこれ一本!QFileInfo::filesystemFilePath()の代替手法と比較

2025-05-31

この関数は、QtのQFileInfoクラスのメンバー関数で、ファイルシステム上のパスをC++17で導入されたstd::filesystem::path型で取得するために使用されます。

QFileInfoクラスについて

まず、QFileInfoは、ファイルやディレクトリに関するシステムに依存しない情報を提供するQtのクラスです。ファイル名、パス、アクセス権、サイズ、最終変更日時などの情報を取得できます。

std::filesystem::pathについて

std::filesystem::pathは、C++17で標準ライブラリに追加されたもので、OSに依存しない形でファイルシステム上のパスを表現し、操作するためのクラスです。これにより、異なるOS(Windows、macOS、Linuxなど)間でパスの記述方法が異なる場合でも、共通のAPIでパスを扱えるようになります。

関数の役割

QFileInfo::filesystemFilePath()は、QFileInfoオブジェクトが参照しているファイルやディレクトリのパスを、std::filesystem::pathオブジェクトとして返します。これは、Qtのファイルシステム関連の機能(QFile, QDirなど)と、C++標準ライブラリのstd::filesystem機能を組み合わせて使用したい場合に非常に便利です。

なぜこの関数が必要か?

  • パス操作の豊富な機能
    std::filesystem::pathは、パスの結合、親パスの取得、ファイル名の抽出、拡張子の変更など、パスを操作するための多くの便利なメソッドを提供しています。この関数を使うことで、QFileInfoで取得したパスに対してこれらのC++標準の機能を利用できるようになります。
  • プラットフォーム非依存性
    std::filesystem::pathは、パスの区切り文字(Windowsでは\、Unix系では/)などを内部で適切に処理してくれるため、開発者がOSの違いを意識することなくパス操作を行うことができます。QFileInfo::filesystemFilePath()もこの利点を引き継ぎます。
  • Qtのパス表現 (QString) とC++標準のパス表現 (std::filesystem::path) の相互運用性
    以前のQtのバージョンでは、ファイルパスは主にQStringとして扱われていました。しかし、C++17でstd::filesystemが導入されたことで、C++のコードベース全体で統一的にパスを扱いたいというニーズが高まりました。この関数は、QFileInfoが持つパス情報をstd::filesystem::path形式で取得できるようにすることで、両者の連携を容易にします。
#include <QFileInfo>
#include <iostream>
#include <filesystem> // std::filesystem::path を使用するために必要

int main() {
    QFileInfo fileInfo("/path/to/your/file.txt"); // QFileInfoオブジェクトを作成

    if (fileInfo.exists()) {
        // QFileInfoからstd::filesystem::pathを取得
        std::filesystem::path fsPath = fileInfo.filesystemFilePath();

        std::cout << "ファイルパス (std::filesystem::path): " << fsPath << std::endl;
        std::cout << "ファイル名: " << fsPath.filename() << std::endl;
        std::cout << "拡張子: " << fsPath.extension() << std::endl;
        std::cout << "親ディレクトリ: " << fsPath.parent_path() << std::endl;
    } else {
        std::cout << "ファイルが見つかりません。" << std::endl;
    }

    return 0;
}


std::filesystem::path QFileInfo::filesystemFilePath() は、Qt の QFileInfo と C++17 の std::filesystem を連携させる便利な機能ですが、いくつか注意すべき点があります。

コンパイルエラー: std::filesystem が見つからない

エラーの例

  • error: 'path' in namespace 'std::filesystem' does not name a type
  • error: 'filesystem' is not a member of 'std'

原因
std::filesystem は C++17 で導入された機能です。プロジェクトが C++17 以降の標準を使用するように設定されていない場合、コンパイラは std::filesystem を認識できません。

トラブルシューティング

  • ヘッダーのインクルード忘れ
    std::filesystem::path を使うためには、<filesystem> ヘッダーをインクルードする必要があります。
    #include <filesystem>
    
  • QMake
    .pro ファイルに以下の行を追加します。
    CONFIG += c++17
    
  • CMake
    CMakeLists.txt に以下の行を追加して、C++標準を C++17 以降に設定します。
    set(CMAKE_CXX_STANDARD 17)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    

ランタイムエラー/不正なパス: パスのエンコーディング問題

原因
ファイルシステムパスのエンコーディングは、OSによって異なります(Windowsでは通常UTF-16、Unix系ではUTF-8など)。QFileInfo は内部でこれを適切に処理しますが、std::filesystem::path との間の変換で問題が発生することがあります。特に、QString から std::string への中間変換を挟む場合、文字エンコーディングの不一致によりパスが壊れる可能性があります。

トラブルシューティング

  • 生文字列リテラル
    コード内でハードコードされたパスを使用する場合、OSのパス区切り文字や特殊文字を扱うために生文字列リテラル(R"()")を使用すると便利です。
    QFileInfo fileInfo(R"(C:\Users\Username\My File.txt)"); // Windows
    QFileInfo fileInfo(R"(/home/username/my_file.txt)");  // Linux/macOS
    
  • デバッグ出力
    qDebug()std::cout でパスを文字列として出力し、文字化けや不正な文字が含まれていないか確認します。
    qDebug() << "QFileInfo path:" << fileInfo.filePath();
    std::cout << "std::filesystem path: " << fileInfo.filesystemFilePath() << std::endl;
    
  • 直接変換の利用
    QFileInfo::filesystemFilePath() は、QString の内部表現から直接 std::filesystem::path に変換するように設計されています。余計な QString::toStdString()std::string から QString への変換を挟まないようにしましょう。

不正確な情報/ファイルが見つからない: QFileInfo の初期化と存在確認

原因
QFileInfo オブジェクトが実際に存在するファイルやディレクトリを参照していない場合、filesystemFilePath() はそのパスを返しますが、そのパスが有効なファイルシステムエントリを指しているとは限りません。

トラブルシューティング

  • パスの絶対化
    相対パスで QFileInfo を初期化した場合、現在の作業ディレクトリ(QDir::currentPath())に依存します。意図しない場所を参照するのを避けるために、QFileInfo::absoluteFilePath()QFileInfo::makeAbsolute() を使ってパスを絶対化することを検討してください。
    QFileInfo relativeFileInfo("my_data/data.csv");
    // 実際に参照される絶対パスを確認
    qDebug() << "Relative path resolves to: " << relativeFileInfo.absoluteFilePath();
    
    // あるいは、QFileInfoを絶対パスで初期化する
    QFileInfo absoluteFileInfo(QDir::currentPath() + "/my_data/data.csv");
    
  • QFileInfo::exists() の使用
    filesystemFilePath() を呼び出す前に、QFileInfo::exists() を使ってファイルやディレクトリが存在するかどうかを確認することが重要です。
    QFileInfo fileInfo("path/to/your/file.txt");
    if (fileInfo.exists()) {
        std::filesystem::path fsPath = fileInfo.filesystemFilePath();
        // パスを使用
    } else {
        qWarning() << "ファイルまたはディレクトリが見つかりません: " << fileInfo.filePath();
    }
    

パフォーマンスの懸念: ファイルシステムアクセス

原因
QFileInfo の一部の関数(例: exists(), size(), lastModified(), isDir(), isFile() など)は、実際にファイルシステムに問い合わせを行うため、パフォーマンスに影響を与える可能性があります。特にネットワークドライブや遅いディスク上のファイルの場合、これらの操作は時間がかかることがあります。

トラブルシューティング

  • std::filesystem との役割分担
    std::filesystem はパスの操作に特化しており、ファイルシステムへの問い合わせは別の関数(std::filesystem::exists(), std::filesystem::file_size() など)で行います。QFileInfo::filesystemFilePath() で取得したパスを std::filesystem の関数に渡すことで、より細かく制御できる場合があります。
  • 必要な情報のみ取得
    本当に必要な情報だけを QFileInfo から取得し、不必要なファイルシステムへのアクセスを避けるようにコードを設計します。
  • キャッシュの利用
    QFileInfo は情報をキャッシュしますが、最新の情報が必要な場合は refresh() を呼び出す必要があります。しかし、無闇な refresh() はパフォーマンスを低下させます。

Windows固有の問題: UNCパスとドライブレター

原因
Windowsでは、ネットワーク共有パス(UNCパス、例: \\Server\Share\file.txt)とドライブレター(例: Z:\file.txt)の扱いに違いがあります。QFileInfostd::filesystem::path もこれらを適切に処理しますが、時折、異なる表現間で問題が生じることがあります。

  • テスト環境での確認
    開発環境だけでなく、ターゲットとなるOS環境(特にネットワークドライブを使用する場合)で十分なテストを行うことが重要です。
  • 一貫したパス形式
    可能であれば、UNCパスを使用するかドライブレターを使用するか、アプリケーション内で一貫したパス形式を維持します。


std::filesystem::path QFileInfo::filesystemFilePath() は、Qt のファイル情報クラス QFileInfo と C++17 のファイルシステムライブラリ std::filesystem を連携させるために使用されます。ここでは、いくつかの具体的な使用例を挙げ、それぞれのコードの目的と動作を説明します。

例 1: 基本的な使用法 - ファイルパスの取得と表示

この例では、QFileInfo を使ってファイルの情報を取得し、そのパスを std::filesystem::path として取得して表示します。

#include <QCoreApplication>
#include <QFileInfo>
#include <QDebug> // qDebug() のために必要
#include <iostream> // std::cout のために必要
#include <filesystem> // std::filesystem::path のために必要

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 存在すると仮定するファイルパス
    // テストのために、実際に存在するファイルパスに置き換えてください
    // 例: QString filePath = "C:/Users/YourUser/Documents/test_file.txt"; (Windows)
    // 例: QString filePath = "/home/youruser/Documents/test_file.txt"; (Linux/macOS)
    QString filePath = "dummy_file.txt"; // 現在のディレクトリにダミーファイルを作成するか、既存のファイルを指定

    // QFileInfo オブジェクトを作成
    QFileInfo fileInfo(filePath);

    qDebug() << "QFileInfo で指定したパス:" << fileInfo.filePath();

    // ファイルが存在するか確認
    if (fileInfo.exists()) {
        qDebug() << "ファイルは存在します。";

        // QFileInfo から std::filesystem::path を取得
        std::filesystem::path fsPath = fileInfo.filesystemFilePath();

        // std::filesystem::path の情報を表示
        std::cout << "std::filesystem::path でのパス: " << fsPath << std::endl;
        std::cout << "ファイル名 (filename()): " << fsPath.filename() << std::endl;
        std::cout << "拡張子 (extension()): " << fsPath.extension() << std::endl;
        std::cout << "親ディレクトリ (parent_path()): " << fsPath.parent_path() << std::endl;
        std::cout << "絶対パス (absolute().string()): " << fsPath.absolute().string() << std::endl; // 絶対パスの取得

        // QFileInfo の他の情報を表示
        qDebug() << "ファイルサイズ:" << fileInfo.size() << "バイト";
        qDebug() << "最終更新日時:" << fileInfo.lastModified().toString(Qt::ISODate);
    } else {
        qWarning() << "指定されたファイルは存在しません。パスを確認してください。";
        qWarning() << "テストのために、手動でファイルを作成するか、正しいパスを指定してください。";
    }

    return 0;
}

説明

  1. インクルード
    • QCoreApplication: Qt アプリケーションの基本的なイベントループを提供します。
    • QFileInfo: ファイル情報クラスです。
    • QDebug: Qt のデバッグ出力 (qDebug(), qWarning()) のために必要です。
    • iostream: C++標準の入出力 (std::cout) のために必要です。
    • filesystem: std::filesystem::path を使用するために必要です。
  2. QFileInfo の作成
    存在すると仮定するファイルパス (filePath) を指定して QFileInfo オブジェクトを初期化します。
  3. 存在確認
    fileInfo.exists() を使って、指定されたファイルが実際に存在するかどうかを確認します。存在しない場合、filesystemFilePath() を呼び出しても意味がないため、このチェックは重要です。
  4. filesystemFilePath() の呼び出し
    fileInfo.filesystemFilePath() を呼び出すことで、QFileInfo が持つパス情報が std::filesystem::path 型のオブジェクトとして取得されます。
  5. std::filesystem::path の利用
    取得した fsPath オブジェクトに対して、std::filesystem::path の様々なメソッド(filename(), extension(), parent_path(), absolute() など)を使ってパスの各要素にアクセスし、表示しています。

例 2: std::filesystemQFileInfo の連携 - ファイルコピーの例

この例では、QFileInfo でファイル情報を取得し、そのパスを std::filesystem::path に変換して、std::filesystem::copy() を使ってファイルをコピーします。

#include <QCoreApplication>
#include <QFileInfo>
#include <QFile> // ファイル操作のために必要
#include <QDir>  // ディレクトリ操作のために必要
#include <QDebug>
#include <iostream>
#include <filesystem>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // テスト用のソースファイルとコピー先のディレクトリを設定
    QString sourceFilePath = "source_file.txt"; // 実行ディレクトリに作成されると仮定
    QString destDir = "copied_files";           // コピー先のディレクトリ名

    // テスト用のソースファイルを作成(存在しない場合)
    if (!QFile::exists(sourceFilePath)) {
        QFile file(sourceFilePath);
        if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
            QTextStream out(&file);
            out << "これはソースファイルの内容です。\n";
            file.close();
            qDebug() << "テスト用ソースファイルが作成されました:" << sourceFilePath;
        } else {
            qWarning() << "ソースファイルを作成できませんでした:" << sourceFilePath;
            return 1;
        }
    }

    // コピー先のディレクトリが存在しない場合は作成
    QDir dir(destDir);
    if (!dir.exists()) {
        if (dir.mkpath(".")) { // "." は現在の QDir オブジェクトが指すパス
            qDebug() << "コピー先ディレクトリが作成されました:" << destDir;
        } else {
            qWarning() << "コピー先ディレクトリを作成できませんでした:" << destDir;
            return 1;
        }
    }

    // QFileInfo を使ってソースファイルの情報を取得
    QFileInfo sourceFileInfo(sourceFilePath);

    if (sourceFileInfo.exists()) {
        // ソースファイルのパスを std::filesystem::path で取得
        std::filesystem::path fsSourcePath = sourceFileInfo.filesystemFilePath();

        // コピー先のパスを std::filesystem::path で構築
        std::filesystem::path fsDestDirPath = QFileInfo(destDir).filesystemFilePath();
        std::filesystem::path fsDestPath = fsDestDirPath / fsSourcePath.filename();

        std::cout << "ソースパス: " << fsSourcePath << std::endl;
        std::cout << "コピー先パス: " << fsDestPath << std::endl;

        try {
            // std::filesystem::copy を使ってファイルをコピー
            std::filesystem::copy(fsSourcePath, fsDestPath, std::filesystem::copy_options::overwrite_existing);
            std::cout << "ファイルが正常にコピーされました。" << std::endl;

            // コピーされたファイルの情報を QFileInfo で確認
            QFileInfo copiedFileInfo(QString::fromStdWString(fsDestPath.wstring())); // std::filesystem::path を QString に変換
            if (copiedFileInfo.exists()) {
                qDebug() << "コピーされたファイルのサイズ:" << copiedFileInfo.size();
            }

        } catch (const std::filesystem::filesystem_error& ex) {
            std::cerr << "ファイルコピー中にエラーが発生しました: " << ex.what() << '\n';
        }
    } else {
        qWarning() << "ソースファイルが見つかりません:" << sourceFilePath;
    }

    return 0;
}

説明

  1. テスト環境の準備
    ソースファイルとコピー先のディレクトリが確実に存在するように、コード内で生成しています。
  2. QFileInfo でソース情報を取得
    コピー元となる source_file.txtQFileInfo を作成します。
  3. filesystemFilePath() でパスを取得
    sourceFileInfo.filesystemFilePath() を使って、コピー元のパスを std::filesystem::path 型で取得します (fsSourcePath)。
  4. コピー先のパス構築
    • コピー先のディレクトリ (destDir) も QFileInfo を通して std::filesystem::path に変換します。
    • std::filesystem::path のオペレータ / を使って、ディレクトリパスとファイル名を結合し、最終的なコピー先パス fsDestPath を構築します。
  5. std::filesystem::copy() でコピー
    std::filesystem::copy() 関数に、取得した fsSourcePath と構築した fsDestPath を渡してファイルをコピーします。std::filesystem::copy_options::overwrite_existing は、同名のファイルが既に存在する場合に上書きするオプションです。
  6. エラーハンドリング
    std::filesystem の関数は std::filesystem::filesystem_error をスローする可能性があるため、try-catch ブロックでエラーを捕捉しています。
  7. std::filesystem::path から QString への変換
    コピー後のファイルの情報を QFileInfo で確認するために、std::filesystem::pathQString に戻す必要があります。Windows 環境では std::filesystem::path::wstring() を使い、それを QString::fromStdWString() で変換するのが最も安全です。Unix 系では std::filesystem::path::string()QString::fromStdString() が使えますが、クロスプラットフォームを考慮すると wstring() が推奨されます。

例 3: ディレクトリ内のファイルを再帰的に検索し、std::filesystem::path で処理

この例では、QDirIterator を使ってディレクトリツリーを走査し、見つかったファイルパスを QFileInfo::filesystemFilePath()std::filesystem::path に変換して表示します。

#include <QCoreApplication>
#include <QDirIterator>
#include <QFileInfo>
#include <QDebug>
#include <iostream>
#include <filesystem>

// 指定されたディレクトリ内のファイルを再帰的にリストアップする関数
void listFilesInDirectory(const QString& directoryPath)
{
    qDebug() << "ディレクトリ内のファイルをリストアップ中:" << directoryPath;

    // QDirIterator を使ってディレクトリを再帰的に走査
    // QDirIterator::Subdirectories でサブディレクトリも含む
    // QDirIterator::FollowSymlinks でシンボリックリンクを辿る
    QDirIterator it(directoryPath, QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);

    while (it.hasNext()) {
        it.next();
        QFileInfo entryInfo = it.fileInfo();

        if (entryInfo.isFile()) {
            // ファイルの場合、QFileInfoからstd::filesystem::pathを取得
            std::filesystem::path fsPath = entryInfo.filesystemFilePath();
            std::cout << "  ファイル: " << fsPath.string() << std::endl; // string() でOS依存の文字列に変換して表示
            // ここで fsPath を使って further std::filesystem operations を実行できます
            // 例: std::cout << "    ファイルサイズ: " << std::filesystem::file_size(fsPath) << " バイト" << std::endl;
        } else if (entryInfo.isDir()) {
            // ディレクトリの場合、再帰的にリストアップする必要がある場合は、
            // QDirIteratorがSubdirectoriesを指定しているため、自動的に処理されます。
            // ここでディレクトリ自体を表示することもできます。
            std::filesystem::path fsDirPath = entryInfo.filesystemFilePath();
            std::cout << "  ディレクトリ: " << fsDirPath.string() << std::endl;
        }
    }
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc);

    // リストアップしたいディレクトリのパスを指定
    // 例: QString targetDir = QDir::currentPath(); // アプリケーションの実行ディレクトリ
    QString targetDir = QDir::homePath(); // ユーザーのホームディレクトリ

    // 関数を呼び出してファイルリストを表示
    listFilesInDirectory(targetDir);

    return 0;
}
  1. listFilesInDirectory 関数
    • QDirIterator: 指定されたディレクトリとそのサブディレクトリを走査するためのQtのクラスです。
    • QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot: ., .. を除いたファイルとディレクトリを対象とします。
    • QDirIterator::Subdirectories: サブディレクトリも再帰的に走査します。
  2. ループ処理
    while (it.hasNext()) { it.next(); } で、次のエントリが存在する限りループを続けます。
  3. QFileInfo の取得
    it.fileInfo() で、現在のエントリの QFileInfo オブジェクトを取得します。
  4. ディレクトリ判定
    entryInfo.isDir() でディレクトリを識別し、表示しています。QDirIterator::Subdirectories を指定しているため、明示的に再帰呼び出しを行う必要はありません。


主に、Qt のパス表現である QString と、C++標準のパス表現である std::filesystem::path および std::string / std::wstring との間で変換を行うことになります。

QString から std::filesystem::path への手動変換

QFileInfo::filesystemFilePath() が導入される以前は、QString から std::filesystem::path を構築するために、手動で変換を行う必要がありました。特に、マルチバイト文字やUnicode文字を含むパスを扱う場合、エンコーディングに注意が必要です。

方法1: QString::toStdString() または QString::toStdWString() を使用

これは最も直接的な方法ですが、エンコーディングに注意が必要です。

  • QString::toStdWString()
    Windows環境では、std::wstring がネイティブなワイド文字(UTF-16)と対応しているため、こちらを使用するのがより安全です。Linux/macOSでは通常 std::string がUTF-8を想定しているので、プラットフォーム間でコードを切り替える必要が出てきます。
  • QString::toStdString()
    Qt 5.0 以降では、QString::toStdString() はデフォルトで UTF-8 エンコーディングを使用します。しかし、これは環境や std::filesystem の実装に依存する可能性があります。特にWindowsでは、ファイルシステムAPIは通常UTF-16(wchar_t)ベースなので、std::string を直接使うと文字化けの問題が発生しやすいです。

コード例

#include <QCoreApplication>
#include <QFileInfo>
#include <QDebug>
#include <iostream>
#include <filesystem>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QString qtPath = "C:/ユーザー/ドキュメント/ファイル名.txt"; // Windowsの例 (日本語パス)
    // QString qtPath = "/home/ユーザー/ドキュメント/ファイル名.txt"; // Linux/macOSの例

    // QFileInfo を作成 (ここでは情報取得のためではなく、パス表現の統一のために使用)
    QFileInfo fileInfo(qtPath);

    // QFileInfo から QString のパスを取得
    QString pathString = fileInfo.filePath();

    // 1. QString::toStdString() を使って std::filesystem::path を構築 (UTF-8を想定)
    // 注意: Windowsでは非推奨。UTF-8エンコーディングが保証されている場合にのみ有効
    std::filesystem::path fsPath1 = pathString.toUtf8().constData();
    std::cout << "Method 1 (UTF-8 via toUtf8): " << fsPath1 << std::endl;

    // 2. QString::toStdWString() を使って std::filesystem::path を構築 (Windows推奨)
    // クロスプラットフォーム対応のため、#ifdef を使うのが一般的
#ifdef Q_OS_WIN
    std::filesystem::path fsPath2 = pathString.toStdWString();
    std::cout << "Method 2 (Windows - via toStdWString): " << fsPath2 << std::endl;
#else
    // Linux/macOS では通常 UTF-8 なので toStdString() を使うか、直接 QString の UTF-8 表現を使う
    std::filesystem::path fsPath2 = pathString.toStdString();
    // または std::filesystem::path fsPath2(pathString.toUtf8().constData());
    std::cout << "Method 2 (Unix-like - via toStdString): " << fsPath2 << std::endl;
#endif

    // 最も安全なのはやはり QFileInfo::filesystemFilePath()
    std::filesystem::path fsPathPreferred = fileInfo.filesystemFilePath();
    std::cout << "Preferred (QFileInfo::filesystemFilePath()): " << fsPathPreferred << std::endl;

    return 0;
}

問題点

  • std::filesystem::path のコンストラクタの曖昧さ
    std::filesystem::pathstd::stringstd::wstring から構築できますが、Windowsでは std::string を使った場合にシステムロケールのエンコーディングを仮定してしまう可能性があり、予期せぬ挙動につながることがあります。std::filesystem::u8path() など、明示的なエンコーディングを指定するファクトリ関数を使うのがより安全です(ただし u8path は C++20 で非推奨になりました)。
  • エンコーディングの不一致
    QString は内部的にUTF-16を使用していますが、std::string は通常システムのロケール依存のエンコーディング(WindowsではShift-JISやCP932、LinuxではUTF-8など)を想定することがあります。このため、直接 toStdString() を使うと、非ASCII文字で問題が発生しやすいです。toUtf8()toLocal8Bit() のように、明示的にエンコーディングを指定して変換する必要があります。

QDir クラスの利用

QFileInfo と同様に、QDir クラスもファイルシステムパスを操作するための豊富な機能を提供します。パスの結合、正規化、ディレクトリの作成など、ファイルやディレクトリの操作に特化しています。

QDir の利点

  • パスの結合・正規化
    filePath(), absoluteFilePath(), cleanPath() など、パスの結合や正規化がQtの機能として行えます。
  • ディレクトリ操作に特化
    mkdir(), rmdir(), cd(), entryList() など、ディレクトリに特化した便利なメソッドが多数あります。

コード例

#include <QCoreApplication>
#include <QDir>
#include <QFileInfo>
#include <QDebug>
#include <iostream>
#include <filesystem>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // QDir を使ってパスを操作
    QDir currentDir = QDir::current();
    QString subDirPath = "data";
    QString fileName = "settings.ini";

    // パスを結合してフルパスを作成
    QString fullFilePath = currentDir.filePath(subDirPath + "/" + fileName);
    qDebug() << "QDir で構築されたパス:" << fullFilePath;

    // QFileInfo を使ってそのパスの情報を取得
    QFileInfo fileInfo(fullFilePath);

    if (fileInfo.exists()) {
        qDebug() << "ファイルは存在します。";
        // QFileInfo::filesystemFilePath() を使う(これが推奨)
        std::filesystem::path fsPath = fileInfo.filesystemFilePath();
        std::cout << "std::filesystem::path (推奨): " << fsPath << std::endl;
    } else {
        qWarning() << "ファイルは存在しません。";
    }

    // QDir から直接 std::filesystem::path を構築することも可能 (ただし、エンコーディングに注意)
    // 通常、QFileInfo::filesystemFilePath() を経由するのが最も安全です。
    std::filesystem::path fsDirFromQString = QDir::currentPath().toStdWString(); // Windows
    // std::filesystem::path fsDirFromQString = QDir::currentPath().toStdString(); // Unix-like
    std::cout << "QDirから直接構築された std::filesystem::path: " << fsDirFromQString << std::endl;


    return 0;
}

注意点

  • QDir 自体は std::filesystem::path を直接返すメソッドを持っていません。そのため、結局 QString に戻し、そこから std::filesystem::path に変換するか、QFileInfo を介して filesystemFilePath() を呼び出すことになります。

C++標準ライブラリ (<filesystem>) のみを使用

Qtのファイルシステムクラス(QFileInfo, QFile, QDir)を一切使わず、C++17の std::filesystem のみを使ってファイルシステム操作を行うことも可能です。これは、Qtへの依存を減らしたい場合や、完全にC++標準に準拠したコードを書きたい場合に有効です。

利点

  • C++標準準拠
    std::filesystem はC++標準の一部であり、将来にわたって互換性が保証されます。
  • Qt への依存なし
    Qt がインストールされていない環境でも動作するコードが書けます。

コード例

#include <iostream>
#include <filesystem> // std::filesystem のために必要

int main()
{
    // 現在の作業ディレクトリのパスを取得
    std::filesystem::path currentPath = std::filesystem::current_path();
    std::cout << "現在のディレクトリ: " << currentPath << std::endl;

    // 新しいディレクトリを作成
    std::filesystem::path newDirPath = currentPath / "new_data_folder";
    if (!std::filesystem::exists(newDirPath)) {
        if (std::filesystem::create_directory(newDirPath)) {
            std::cout << "ディレクトリを作成しました: " << newDirPath << std::endl;
        } else {
            std::cerr << "ディレクトリの作成に失敗しました: " << newDirPath << std::endl;
        }
    } else {
        std::cout << "ディレクトリは既に存在します: " << newDirPath << std::endl;
    }

    // ファイルパスを構築
    std::filesystem::path filePath = newDirPath / "example.txt";
    std::cout << "ファイルパス: " << filePath << std::endl;

    // ファイルが存在するか確認
    if (std::filesystem::exists(filePath)) {
        std::cout << "ファイルは存在します。" << std::endl;
        std::cout << "ファイルサイズ: " << std::filesystem::file_size(filePath) << " バイト" << std::endl;
    } else {
        std::cout << "ファイルは存在しません。" << std::endl;
    }

    // ディレクトリを走査
    std::cout << "\nディレクトリの内容:\n";
    for (const auto& entry : std::filesystem::directory_iterator(currentPath)) {
        std::cout << "  " << entry.path().filename() << (entry.is_directory() ? " (ディレクトリ)" : " (ファイル)") << std::endl;
    }

    // ディレクトリの削除 (例として。注意して使用してください)
    // if (std::filesystem::exists(newDirPath)) {
    //     std::filesystem::remove_all(newDirPath);
    //     std::cout << "ディレクトリと内容を削除しました: " << newDirPath << std::endl;
    // }

    return 0;
}

注意点

  • ファイルの内容の読み書きには、C++標準のストリーム (std::ifstream, std::ofstream) や、Qt の QFilestd::filesystem::path を使って開く方法を検討する必要があります(Qt 6 から QFile のコンストラクタに std::filesystem::path を直接渡せるようになっています)。
  • std::filesystemQFileInfo が提供する一部の機能(例: Qtリソースシステムとの連携)を直接提供しません。

std::filesystem::path QFileInfo::filesystemFilePath() は、Qt と C++17 の std::filesystem を効果的に橋渡しする、推奨される方法です。Qt 6 以降では、QFileQDir のコンストラクタやメソッドでも std::filesystem::path を直接受け取れるようになり、さらに連携がスムーズになっています。

しかし、以下のような場合は代替方法を検討することになります。

  • 特定のエンコーディング処理が必要
    特殊なエンコーディングのパスを扱う場合、QStringtoUtf8(), toLocal8Bit(), toStdWString() などと std::filesystem::path のコンストラクタや u8path() などを組み合わせて、より詳細な制御が必要になることがあります。
  • Qt への依存を避けたい
    純粋なC++標準コードとしてファイルシステム操作を行いたい場合は、std::filesystem のみを使用します。
  • Qt 5 以前のバージョンを使用している
    filesystemFilePath() が存在しないため、手動で QStringstd::filesystem::path の変換を行う必要があります(特にエンコーディングに注意)。