Qt QFileInfo::birthTime()徹底解説:ファイルの作成日時を正確に取得する方法

2025-05-31

QtプログラミングにおけるQFileInfo::birthTime()は、ファイルが作成された日時(生成日時)を返す関数です。

もう少し詳しく説明すると、以下のようになります。

  • 注意点:
    • OSやファイルシステムによる制限: ファイルの作成日時(birth time)は、すべてのオペレーティングシステムやファイルシステムで利用できるわけではありません。例えば、一部のLinuxファイルシステム(EXT2/3など)では、デフォルトで作成日時が記録されない場合があります。このような場合、birthTime()は無効なQDateTimeオブジェクトを返します。
    • Qtのバージョン: birthTime()関数はQt 5.10で導入されました。それより古いQtのバージョンでは利用できません。
    • created()との違い: かつてはcreated()という関数もありましたが、これは非推奨(deprecated)となり、birthTime()またはmetadataChangeTime()の使用が推奨されています。created()はファイルのメタデータが最後に変更された時刻を返すことが多かったため、純粋な作成日時とは異なる場合がありました。
  • 返り値: QDateTimeオブジェクトを返します。このQDateTimeオブジェクトには、年、月、日、時、分、秒などの情報が含まれます。
  • どのクラスの関数か?: QtのQFileInfoクラスのメンバー関数です。QFileInfoは、ファイルのパス、サイズ、アクセス権、最終更新日時など、ファイルに関する様々な情報を取得するために使われます。
  • 何をする関数か?: ファイルシステム上の特定のファイルについて、そのファイルが「いつ誕生したか」、つまり「いつ作成されたか」という情報をQDateTime型で取得します。
#include <QCoreApplication>
#include <QFileInfo>
#include <QDateTime>
#include <QDebug> // デバッグ出力用

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

    QString filePath = "my_file.txt"; // 調べたいファイルのパス

    // テスト用のファイルを作成 (ファイルが存在しない場合)
    QFile file(filePath);
    if (!file.exists()) {
        if (file.open(QIODevice::WriteOnly)) {
            file.write("Hello, Qt!");
            file.close();
            qDebug() << "ファイルが作成されました: " << filePath;
        } else {
            qDebug() << "ファイルの作成に失敗しました: " << filePath;
            return 1;
        }
    }

    QFileInfo fileInfo(filePath);

    if (fileInfo.exists()) {
        QDateTime birthTime = fileInfo.birthTime();

        if (birthTime.isValid()) {
            qDebug() << "ファイルの作成日時: " << birthTime.toString(Qt::ISODate);
        } else {
            qDebug() << "ファイルの作成日時を取得できませんでした (OS/ファイルシステムの制限の可能性あり)。";
        }

        // その他の日時情報
        qDebug() << "最終変更日時: " << fileInfo.lastModified().toString(Qt::ISODate);
        qDebug() << "最終アクセス日時: " << fileInfo.lastRead().toString(Qt::ISODate);
    } else {
        qDebug() << "ファイルが見つかりません: " << filePath;
    }

    return a.exec();
}


QDateTimeが不正な値(invalid)を返す

エラー/症状
fileInfo.birthTime().isValid()falseを返す、または取得した日時が明らかに間違っている(例:1970年1月1日など)。

原因

  • Qtのバージョンが古い
    birthTime()関数はQt 5.10で導入されました。それより古いQtのバージョンを使用している場合、この関数は利用できません。
  • ファイルが存在しない、またはパスが間違っている
    QFileInfoオブジェクトが指すファイルが存在しない場合、ファイル情報は取得できません。
  • ファイルシステムが作成日時をサポートしていない
    特に古いLinuxファイルシステム(例: ext2/3)では、ファイルの作成日時(birth time)がデフォルトで記録されないことがあります。birthTime()は、OSがこの情報を提供しない場合、無効なQDateTimeを返します。

トラブルシューティング

  • Qtのバージョンを確認する
    使用しているQtのバージョンが5.10以降であることを確認してください。
  • ファイルパスを確認する
    QFileInfo(filePath).exists()でファイルが存在するか確認し、パスが正しいことを確かめてください。相対パスを使用している場合は、現在の作業ディレクトリからの相対パスであることを意識してください。
  • 代替の日時情報を使用する
    作成日時が利用できない場合でも、lastModified()(最終変更日時)やlastRead()(最終アクセス日時)はほとんどのシステムで利用可能です。これらの情報で要件を満たせるか検討してください。
    qDebug() << "最終変更日時: " << fileInfo.lastModified().toString();
    qDebug() << "最終アクセス日時: " << fileInfo.lastRead().toString();
    
  • isValid()で確認する
    常にbirthTime().isValid()を呼び出して、取得した日時が有効かどうかを確認してください。
    QDateTime birthTime = fileInfo.birthTime();
    if (birthTime.isValid()) {
        qDebug() << "作成日時: " << birthTime.toString();
    } else {
        qDebug() << "作成日時を取得できませんでした。OSまたはファイルシステムがサポートしていない可能性があります。";
    }
    

作成日時が更新されない、または予期せぬ古い日時を返す

エラー/症状
ファイルをコピーしたり、上書き保存したりしたにもかかわらず、birthTime()が期待する新しい日時ではなく、古い日時を返す。

原因

  • ファイルシステム/OSの動作
    特定のファイルシステムやOSのバージョンでは、ファイルの作成日時(birth time)の扱いが直感的でない場合があります。例えば、Windowsでは通常作成日時が更新されますが、Unix系では元の作成日時が保持されやすい傾向があります。
  • ファイルのコピー方法
    ファイルをコピーした場合、OSによってはコピー元の作成日時が引き継がれることがあります。また、単にファイルを上書きした場合、既存のinode(ファイルシステム上のファイル実体を指すデータ構造)が再利用され、作成日時が更新されないことがあります。

トラブルシューティング

  • lastModified()との比較
    作成日時が期待通りに動作しない場合、ファイルの「最終変更日時」であるlastModified()の方が、ユーザーがファイルを更新したタイミングを示す正確な情報である可能性があります。どちらの日時が必要か、アプリケーションの要件を再検討してください。
  • ファイルの再作成を検討する
    ファイルの作成日時を確実に更新したい場合は、既存のファイルを一度削除し、新しいファイルとして作成し直すことで、新しい作成日時が記録されます。
    QString filePath = "test.txt";
    QFile::remove(filePath); // 既存ファイルを削除
    QFile newFile(filePath);
    if (newFile.open(QIODevice::WriteOnly)) {
        newFile.write("New content.");
        newFile.close();
        qDebug() << "新しくファイルを作成しました。";
    }
    QFileInfo newFileInfo(filePath);
    if (newFileInfo.birthTime().isValid()) {
        qDebug() << "新しいファイルの作成日時: " << newFileInfo.birthTime().toString();
    }
    

ネットワークドライブやNFS上のファイルで動作が遅い、または不安定

エラー/症状
ネットワーク共有上のファイルに対してQFileInfo::birthTime()を呼び出すと、アプリケーションが一時的にフリーズしたり、非常に遅くなったりする。

原因

  • サーバー側の機能制限
    ネットワークファイルシステムによっては、birthTimeのような詳細なファイル情報が提供されない、または提供されるまでに時間がかかる場合があります。
  • ネットワークI/Oのオーバーヘッド
    ネットワークドライブやNFS上のファイルに対してファイル情報を取得する場合、ネットワーク経由での通信が発生するため、ローカルファイルに比べて大幅に時間がかかります。

トラブルシューティング

  • 必要な情報のみ取得する
    本当にbirthTimeが必要なのか、それともlastModifiedで十分なのかを再確認してください。不要な情報取得は避けるべきです。
  • 非同期処理
    ファイル情報の取得処理をメインスレッドから切り離し、別スレッドで実行することで、UIのフリーズを防ぎ、ユーザーエクスペリエンスを向上させることができます。QtのQRunnableQtConcurrentQThreadなどを活用してください。
  • 情報のキャッシュ
    頻繁にアクセスするファイルの場合、一度取得したQFileInfoオブジェクトや、必要な日時情報をアプリケーション内でキャッシュすることを検討してください。ただし、ファイルが外部で変更される可能性を考慮し、定期的なリフレッシュが必要になる場合があります。
  • デバッグ出力の活用
    qDebug()を使用して、取得した日時やisValid()の結果をコンソールに出力し、問題の切り分けに役立ててください。
  • ドキュメントの確認
    使用しているQtのバージョンとOSにおけるQFileInfo::birthTime()の具体的な動作について、Qtの公式ドキュメント(QFileInfoクラスリファレンス)を常に確認することをお勧めします。特に、OSごとの動作の違いに関する記述は重要です。
  • エラーハンドリングの徹底
    QFileInfo::exists()QDateTime::isValid()などで、必ずファイルの存在確認や取得したデータの有効性確認を行うようにしてください。


基本的なファイル作成日時の取得

最も基本的な使い方です。特定のファイルの作成日時を取得し、コンソールに表示します。

#include <QCoreApplication>
#include <QFileInfo>
#include <QDateTime>
#include <QDebug> // デバッグ出力用

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

    // 調べたいファイルのパスを指定
    // ここでは実行ファイルと同じディレクトリにある "example.txt" を想定します。
    // 存在しない場合は、後で作成します。
    QString filePath = "example.txt";

    // ファイルが存在しない場合は作成
    QFile file(filePath);
    if (!file.exists()) {
        if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
            file.write("これはテストファイルです。\n");
            file.write("Hello, QFileInfo::birthTime()!");
            file.close();
            qDebug() << "ファイルが作成されました:" << filePath;
        } else {
            qDebug() << "ファイルの作成に失敗しました:" << filePath;
            return 1; // エラー終了
        }
    }

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

    // ファイルが存在することを確認
    if (fileInfo.exists()) {
        // birthTime() を呼び出して作成日時を取得
        QDateTime birthTime = fileInfo.birthTime();

        // 取得した日時が有効かどうかを確認
        if (birthTime.isValid()) {
            qDebug() << "ファイル名:" << fileInfo.fileName();
            qDebug() << "ファイルの作成日時 (birthTime):" << birthTime.toString(Qt::ISODate);
            // その他の日時情報も取得してみる
            qDebug() << "最終変更日時 (lastModified):" << fileInfo.lastModified().toString(Qt::ISODate);
            qDebug() << "最終アクセス日時 (lastRead):" << fileInfo.lastRead().toString(Qt::ISODate);
            qDebug() << "メタデータ変更日時 (metadataChangeTime):" << fileInfo.metadataChangeTime().toString(Qt::ISODate);
        } else {
            qDebug() << "ファイルの作成日時を取得できませんでした。";
            qDebug() << "このOSまたはファイルシステムでは birthTime() がサポートされていない可能性があります。";
        }
    } else {
        qDebug() << "エラー: ファイルが見つかりません:" << filePath;
    }

    return 0; // 正常終了
}

解説

  • QDateTime::toString(Qt::ISODate) は、日時をISO 8601形式(例: 2025-05-31T06:27:45)でフォーマットして出力します。
  • birthTime.isValid() が重要です。birthTime() がサポートされていない環境では、無効な QDateTime が返されるため、このチェックが必要です。
  • fileInfo.birthTime() を呼び出して、QDateTime オブジェクトとして作成日時を取得します。
  • file.exists() でファイルが実際に存在するかどうかを確認します。存在しない場合は、QFile を使って簡単なファイルを作成しています。これにより、確実にbirthTime()をテストできます。
  • QFileInfo オブジェクトをファイルのパスで初期化します。
  • QCoreApplication はQtアプリケーションの基本的なイベントループを提供します。コンソールアプリケーションでも必要です。

ディレクトリ内の全ファイルの作成日時をリスト表示

特定のディレクトリ内のすべてのファイル(サブディレクトリを除く)について、ファイル名と作成日時を一覧表示する例です。

#include <QCoreApplication>
#include <QDir>
#include <QFileInfo>
#include <QDateTime>
#include <QDebug>

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

    QString directoryPath = "."; // カレントディレクトリを指定

    QDir dir(directoryPath);

    if (!dir.exists()) {
        qDebug() << "エラー: ディレクトリが見つかりません:" << directoryPath;
        return 1;
    }

    // ディレクトリ内のすべてのファイル情報(サブディレクトリは除く)を取得
    // QDir::NoDotAndDotDot: "." と ".." を除外
    // QDir::Files: ファイルのみを取得
    QFileInfoList fileList = dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot);

    if (fileList.isEmpty()) {
        qDebug() << "ディレクトリにファイルがありません:" << directoryPath;
    } else {
        qDebug() << "ディレクトリ内のファイルと作成日時:";
        for (const QFileInfo &fileInfo : fileList) {
            QDateTime birthTime = fileInfo.birthTime();

            if (birthTime.isValid()) {
                qDebug() << "  " << fileInfo.fileName().toLeftJustified(20) << birthTime.toString(Qt::ISODate);
            } else {
                qDebug() << "  " << fileInfo.fileName().toLeftJustified(20) << "作成日時不明 (非サポート)";
            }
        }
    }

    return 0;
}

解説

  • toLeftJustified(20) は、ファイル名を20文字幅で左寄せにするためのフォーマットです(出力を見やすくするため)。
  • 取得した QFileInfoList をループで処理し、各ファイルの birthTime() を取得して表示します。
  • dir.entryInfoList() で指定されたフィルタ(QDir::Files | QDir::NoDotAndDotDot)に基づいて、ディレクトリ内のファイル情報のリストを取得します。
  • QDir クラスを使用してディレクトリを扱います。

ファイルのタイムスタンプを比較する

ファイルの作成日時や最終変更日時を比較して、どちらが新しいか、または同じかを確認する例です。

#include <QCoreApplication>
#include <QFileInfo>
#include <QDateTime>
#include <QDebug>
#include <QFile>

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

    QString file1Path = "file1.txt";
    QString file2Path = "file2.txt";

    // テストファイルを作成
    QFile file1(file1Path);
    if (!file1.exists()) {
        file1.open(QIODevice::WriteOnly); file1.write("Content for file 1."); file1.close();
        qDebug() << "作成:" << file1Path;
    }
    QFile file2(file2Path);
    if (!file2.exists()) {
        // 少し時間を置いてファイル2を作成
        QThread::msleep(100); // 100ミリ秒待機
        file2.open(QIODevice::WriteOnly); file2.write("Content for file 2."); file2.close();
        qDebug() << "作成:" << file2Path;
    }

    QFileInfo info1(file1Path);
    QFileInfo info2(file2Path);

    if (!info1.exists() || !info2.exists()) {
        qDebug() << "エラー: ファイルが存在しません。";
        return 1;
    }

    QDateTime birth1 = info1.birthTime();
    QDateTime birth2 = info2.birthTime();

    if (birth1.isValid() && birth2.isValid()) {
        qDebug() << file1Path << "作成日時:" << birth1.toString(Qt::ISODate);
        qDebug() << file2Path << "作成日時:" << birth2.toString(Qt::ISODate);

        if (birth1 < birth2) {
            qDebug() << file1Path << "の方が" << file2Path << "より古い作成日時です。";
        } else if (birth1 > birth2) {
            qDebug() << file1Path << "の方が" << file2Path << "より新しい作成日時です。";
        } else {
            qDebug() << "両ファイルの作成日時は同じです。";
        }
    } else {
        qDebug() << "少なくとも1つのファイルの作成日時が取得できませんでした。";
    }

    // 最終変更日時の比較も同様に行えます
    QDateTime modified1 = info1.lastModified();
    QDateTime modified2 = info2.lastModified();

    qDebug() << "\n--- 最終変更日時の比較 ---";
    qDebug() << file1Path << "最終変更日時:" << modified1.toString(Qt::ISODate);
    qDebug() << file2Path << "最終変更日時:" << modified2.toString(Qt::ISODate);

    if (modified1 < modified2) {
        qDebug() << file1Path << "の方が" << file2Path << "より古い最終変更日時です。";
    } else if (modified1 > modified2) {
        qDebug() << file1Path << "の方が" << file2Path << "より新しい最終変更日時です。";
    } else {
        qDebug() << "両ファイルの最終変更日時は同じです。";
    }

    return 0;
}
  • lastModified() も同様に比較できることを示しています。
  • 取得した QDateTime オブジェクトは、<> といった比較演算子で直接比較できます。これは、日時が内部的に数値として表現されているためです。
  • 2つの異なるファイルを作成し、QThread::msleep(100) を使ってわずかに時間差を設けています。これにより、birthTime() が異なる値になる可能性が高まります。


QFileInfo::birthTime()が利用できない、または要件に合わない場合、以下の代替方法を検討できます。

QFileInfo::lastModified() (最終変更日時) を使用する

説明
ファイルが最後に変更された日時を返します。多くのOSやファイルシステムで確実にサポートされており、birthTime()よりも信頼性が高い場合があります。