【Qt】QFileInfo::suffix()でハマらない!よくあるエラーとトラブルシューティング

2025-06-01

QFileInfo::suffix() は、QFileInfo クラスのメンバ関数の一つで、ファイル名から 拡張子 を取得するために使われます。

具体的には、QFileInfo オブジェクトが表すファイルのファイル名(ベース名)から、最後のドット (.) 以降の文字列を返します。もしファイル名にドットが含まれていない場合や、ファイル名がドットで終わる場合は、空の文字列 ("") を返します。


  • ファイル名が "config." の場合、ドットで終わっているため、suffix()"" を返します。
  • ファイル名が "README" の場合、ドットが含まれていないため、suffix()"" を返します。
  • ファイル名が "archive.tar.gz" の場合、suffix()"gz" を返します。
  • ファイル名が "image.jpeg" の場合、suffix()"jpeg" を返します。
  • ファイル名が "document.txt" の場合、suffix()"txt" を返します。

使い方

QFileInfo オブジェクトを作成し、そのオブジェクトに対して suffix() 関数を呼び出すことで、拡張子を取得できます。

#include <QFileInfo>
#include <QString>
#include <QDebug>

int main() {
    QFileInfo fileInfo1("document.txt");
    QString suffix1 = fileInfo1.suffix();
    qDebug() << "Suffix of document.txt:" << suffix1; // 出力: Suffix of document.txt: "txt"

    QFileInfo fileInfo2("image.jpeg");
    QString suffix2 = fileInfo2.suffix();
    qDebug() << "Suffix of image.jpeg:" << suffix2;   // 出力: Suffix of image.jpeg: "jpeg"

    QFileInfo fileInfo3("archive.tar.gz");
    QString suffix3 = fileInfo3.suffix();
    qDebug() << "Suffix of archive.tar.gz:" << suffix3; // 出力: Suffix of archive.tar.gz: "gz"

    QFileInfo fileInfo4("README");
    QString suffix4 = fileInfo4.suffix();
    qDebug() << "Suffix of README:" << suffix4;      // 出力: Suffix of README: ""

    QFileInfo fileInfo5("config.");
    QString suffix5 = fileInfo5.suffix();
    qDebug() << "Suffix of config.:" << suffix5;     // 出力: Suffix of config.: ""

    return 0;
}

このように、QFileInfo::suffix() を使うと、ファイルの種類を判別したり、特定の拡張子を持つファイルをフィルタリングしたりする際に便利です。



ファイル名にドット (.) が含まれていない場合

  • 対処法
    • ファイル名に拡張子が含まれているべきか確認してください。
    • 拡張子がないファイル(例:README、設定ファイルなど)である可能性を考慮し、空の文字列が返ってきた場合の処理を適切に記述してください。
  • 理由
    suffix() は最後のドット以降の文字列を拡張子とみなすため、ドットがないファイル名には拡張子が存在しないと判断されます。
  • 現象
    suffix() を呼び出しても空の文字列 ("") が返ってくる。

ファイル名がドット (.) で終わる場合

  • 対処法
    • ファイル名が意図した通りであるか確認してください。
    • もしファイル名に誤りがある場合は修正する必要があります。
  • 理由
    拡張子はドットの後の文字列であるため、ドットで終わるファイル名には拡張子が存在しないと判断されます。
  • 現象
    suffix() を呼び出しても空の文字列 ("") が返ってくる。

複数のドット (.) がファイル名に含まれる場合

  • 対処法
    • 複合的な拡張子(例:.tar.gz)全体を取得したい場合は、QFileInfo::fileName() を使ってファイル名全体を取得し、自分で文字列操作を行う必要があります。例えば、最後のドットより前の部分をベース名とし、それ以降を拡張子として扱うなどのロジックを実装します。
    • QFileInfo::completeSuffix() を使うと、最初のドットを含むそれ以降のすべての部分(上記の例では "tar.gz")を取得できます。どちらの関数が目的に合っているか検討してください。
  • 理由
    suffix() の仕様によるものです。
  • 現象
    suffix() は最後のドット以降の文字列のみを拡張子として返します。例えば、"archive.tar.gz" の場合、"gz" が返ります。

大文字・小文字の区別

  • 対処法
    • 拡張子を比較する前に、QString::toLower()QString::toUpper() を使ってケースを統一してください。
    • Qt の文字列比較には、大文字・小文字を区別しないオプションを持つ関数(例:QString::compare() の Qt::CaseInsensitive フラグ)もあります。
  • 理由
    QString の比較はデフォルトで大文字・小文字を区別します。
  • 現象
    拡張子の比較を行う際に、大文字・小文字が区別されてしまう。例えば、"image.JPG"suffix()"JPG" を返しますが、"jpg" と比較すると不一致となります。

ファイルパスではなくファイル名のみを QFileInfo に渡している場合

  • 対処法
    • QFileInfo には必ず正しいファイルパスまたはファイル名のみを渡してください。
    • 必要であれば、QDir クラスなどを使ってパスを操作し、ファイル名部分のみを抽出してから QFileInfo を作成することを検討してください。
  • 理由
    QFileInfo は渡された文字列全体をファイルパスまたはファイル名として解釈します。
  • 現象
    ファイルパスの一部にドットが含まれていると、意図しない拡張子が返ってくる可能性があります。
  • 具体的な例でテスト
    問題が発生しているファイル名やパスの具体的な例を使って、コードを部分的にテストしてみることで、原因を特定しやすくなります。
  • ドキュメントの確認
    QFileInfo::suffix() や関連する QFileInfo のメンバ関数のドキュメントを再度確認し、仕様を正しく理解することが重要です。
  • qDebug() の活用
    取得した拡張子を qDebug() で出力して、実際の内容を確認することが有効です。


基本的な使い方

#include <QCoreApplication>
#include <QFileInfo>
#include <QString>
#include <QDebug>

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

    // ファイルパスの文字列から QFileInfo オブジェクトを作成
    QFileInfo fileInfo1("my_document.txt");
    QString suffix1 = fileInfo1.suffix();
    qDebug() << "my_document.txt の拡張子:" << suffix1; // 出力: my_document.txt の拡張子: "txt"

    QFileInfo fileInfo2("/path/to/image.jpeg");
    QString suffix2 = fileInfo2.suffix();
    qDebug() << "/path/to/image.jpeg の拡張子:" << suffix2; // 出力: /path/to/image.jpeg の拡張子: "jpeg"

    QFileInfo fileInfo3("archive.tar.gz");
    QString suffix3 = fileInfo3.suffix();
    qDebug() << "archive.tar.gz の拡張子:" << suffix3; // 出力: archive.tar.gz の拡張子: "gz"

    QFileInfo fileInfo4("no_extension");
    QString suffix4 = fileInfo4.suffix();
    qDebug() << "no_extension の拡張子:" << suffix4; // 出力: no_extension の拡張子: ""

    QFileInfo fileInfo5("file_with_dot.");
    QString suffix5 = fileInfo5.suffix();
    qDebug() << "file_with_dot. の拡張子:" << suffix5; // 出力: file_with_dot. の拡張子: ""

    return a.exec();
}

この例では、様々なファイル名に対して QFileInfo::suffix() を呼び出し、その結果を qDebug() で出力しています。基本的なファイル名、パス付きのファイル名、複数のドットを含むファイル名、拡張子のないファイル名、ドットで終わるファイル名など、様々なケースでの suffix() の挙動を確認できます。

特定の拡張子を持つファイルをフィルタリングする

#include <QDir>
#include <QFileInfo>
#include <QStringList>
#include <QDebug>

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

    QDir directory("."); // 現在のディレクトリを対象とする

    // ディレクトリ内のすべてのファイルとディレクトリのリストを取得
    QFileInfoList entries = directory.entryInfoList(QDir::Files | QDir::NoDotAndDotDot);

    QStringList imageFiles;

    // 各エントリをチェックし、拡張子が "jpg" または "png" のファイルを探す
    foreach (const QFileInfo &fileInfo, entries) {
        QString suffix = fileInfo.suffix().toLower(); // 拡張子を小文字に変換して比較
        if (suffix == "jpg" || suffix == "png") {
            imageFiles << fileInfo.fileName();
        }
    }

    qDebug() << "画像ファイル (jpg, png):" << imageFiles;

    return a.exec();
}

この例では、現在のディレクトリ内のファイルを検索し、拡張子が "jpg" または "png" であるファイルの名前をリストアップしています。suffix() で取得した拡張子を toLower() で小文字に変換してから比較することで、大文字・小文字の違いを吸収しています。

ファイルの種類に応じて処理を分岐する

#include <QCoreApplication>
#include <QFileInfo>
#include <QString>
#include <QDebug>

void processFile(const QFileInfo &fileInfo) {
    QString suffix = fileInfo.suffix().toLower();
    QString fileName = fileInfo.fileName();

    if (suffix == "txt") {
        qDebug() << fileName << ": テキストファイルとして処理します。";
        // テキストファイル固有の処理
    } else if (suffix == "jpg" || suffix == "jpeg" || suffix == "png") {
        qDebug() << fileName << ": 画像ファイルとして処理します。";
        // 画像ファイル固有の処理
    } else if (suffix == "zip" || suffix == "tar.gz") {
        qDebug() << fileName << ": アーカイブファイルとして処理します。";
        // アーカイブファイル固有の処理
    } else {
        qDebug() << fileName << ": 不明なファイル形式です。";
    }
}

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

    processFile(QFileInfo("report.txt"));
    processFile(QFileInfo("photo.jpg"));
    processFile(QFileInfo("data.tar.gz"));
    processFile(QFileInfo("unknown.dat"));

    return a.exec();
}

この例では、processFile 関数が QFileInfo オブジェクトを受け取り、その拡張子に基づいて異なる処理を行います。suffix() で取得した拡張子を使って if-else if 文で条件分岐しています。複合的な拡張子 "tar.gz""gz" として認識されることに注意してください。

#include <QCoreApplication>
#include <QFileInfo>
#include <QString>
#include <QDebug>

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

    QFileInfo fileInfo("archive.tar.gz");
    QString suffix = fileInfo.suffix();
    QString completeSuffix = fileInfo.completeSuffix();

    qDebug() << "archive.tar.gz の suffix():" << suffix;         // 出力: archive.tar.gz の suffix(): "gz"
    qDebug() << "archive.tar.gz の completeSuffix():" << completeSuffix; // 出力: archive.tar.gz の completeSuffix(): "tar.gz"

    return a.exec();
}


QString::split() と文字列操作

ファイル名を文字列として扱い、QString::split() 関数を使ってドット (.) で分割し、最後の要素を拡張子として取得する方法です。

#include <QCoreApplication>
#include <QString>
#include <QDebug>

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

    QString fileName1 = "document.txt";
    QStringList parts1 = fileName1.split('.');
    QString suffix1 = parts1.size() > 1 ? parts1.last() : "";
    qDebug() << fileName1 << " の拡張子 (split):" << suffix1; // 出力: document.txt の拡張子 (split): "txt"

    QString fileName2 = "archive.tar.gz";
    QStringList parts2 = fileName2.split('.');
    QString suffix2 = parts2.size() > 1 ? parts2.last() : "";
    qDebug() << fileName2 << " の拡張子 (split):" << suffix2; // 出力: archive.tar.gz の拡張子 (split): "gz"

    QString fileName3 = "no_extension";
    QStringList parts3 = fileName3.split('.');
    QString suffix3 = parts3.size() > 1 ? parts3.last() : "";
    qDebug() << fileName3 << " の拡張子 (split):" << suffix3; // 出力: no_extension の拡張子 (split): ""

    return a.exec();
}

利点

  • 分割された各部分を利用して、より複雑なファイル名解析が可能です。
  • 複数のドットがあるファイル名でも、最後のドット以降を正確に取得できます。

注意点

  • ドットがないファイル名の場合、空の文字列を適切に処理する必要があります。

QString::lastIndexOf() と QString::mid()

ファイル名の中で最後のドットの位置を QString::lastIndexOf() で探し、その位置以降の文字列を QString::mid() で抽出する方法です。

#include <QCoreApplication>
#include <QString>
#include <QDebug>

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

    QString fileName1 = "document.txt";
    int lastDot1 = fileName1.lastIndexOf('.');
    QString suffix1 = (lastDot1 != -1) ? fileName1.mid(lastDot1 + 1) : "";
    qDebug() << fileName1 << " の拡張子 (lastIndexOf/mid):" << suffix1; // 出力: document.txt の拡張子 (lastIndexOf/mid): "txt"

    QString fileName2 = "archive.tar.gz";
    int lastDot2 = fileName2.lastIndexOf('.');
    QString suffix2 = (lastDot2 != -1) ? fileName2.mid(lastDot2 + 1) : "";
    qDebug() << fileName2 << " の拡張子 (lastIndexOf/mid):" << suffix2; // 出力: archive.tar.gz の拡張子 (lastIndexOf/mid): "gz"

    QString fileName3 = "no_extension";
    int lastDot3 = fileName3.lastIndexOf('.');
    QString suffix3 = (lastDot3 != -1) ? fileName3.mid(lastDot3 + 1) : "";
    qDebug() << fileName3 << " の拡張子 (lastIndexOf/mid):" << suffix3; // 出力: no_extension の拡張子 (lastIndexOf/mid): ""

    return a.exec();
}

利点

  • 最後のドットの位置を直接取得できるため、処理がシンプルになります。
  • split() よりも効率的な場合があります(特に大きな文字列の場合)。

注意点

  • ドットがないファイル名の場合、lastIndexOf() は -1 を返すため、その場合の処理が必要です。

正規表現 (QRegularExpression)

より複雑なパターンに一致する拡張子を抽出したい場合に、正規表現を利用できます。

#include <QCoreApplication>
#include <QString>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
#include <QDebug>

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

    QString fileName1 = "document.txt";
    QRegularExpression re1("\\.([^.]+)$");
    QRegularExpressionMatch match1 = re1.match(fileName1);
    QString suffix1 = match1.hasMatch() ? match1.captured(1) : "";
    qDebug() << fileName1 << " の拡張子 (正規表現):" << suffix1; // 出力: document.txt の拡張子 (正規表現): "txt"

    QString fileName2 = "archive.tar.gz";
    QRegularExpression re2("\\.([^.]+)$");
    QRegularExpressionMatch match2 = re2.match(fileName2);
    QString suffix2 = match2.hasMatch() ? match2.captured(1) : "";
    qDebug() << fileName2 << " の拡張子 (正規表現):" << suffix2; // 出力: archive.tar.gz の拡張子 (正規表現): "gz"

    QString fileName3 = "image.with.dots.jpeg";
    QRegularExpression re3("\\.([^.]+)$");
    QRegularExpressionMatch match3 = re3.match(fileName3);
    QString suffix3 = match3.hasMatch() ? match3.captured(1) : "";
    qDebug() << fileName3 << " の拡張子 (正規表現):" << suffix3; // 出力: image.with.dots.jpeg の拡張子 (正規表現): "jpeg"

    return a.exec();
}

利点

  • 非常に柔軟なパターンマッチングが可能です。例えば、特定の文字種の拡張子のみを抽出したり、複数の可能性のある拡張子に対応したりできます。

注意点

  • 簡単な拡張子抽出にはオーバースペックになる可能性があります。
  • 正規表現の記述と理解がやや難しい場合があります。

QFileInfo::completeSuffix() の利用

もし、複数のドットを含むファイル名で、最初のドット以降のすべての部分を拡張子とみなしたい場合は、QFileInfo::completeSuffix() を使用できます。これは suffix() の代替というよりは、異なるニーズに対応する関数です。

#include <QCoreApplication>
#include <QFileInfo>
#include <QString>
#include <QDebug>

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

    QFileInfo fileInfo1("archive.tar.gz");
    QString completeSuffix1 = fileInfo1.completeSuffix();
    qDebug() << "archive.tar.gz の completeSuffix():" << completeSuffix1; // 出力: archive.tar.gz の completeSuffix(): "tar.gz"

    QFileInfo fileInfo2("document.txt");
    QString completeSuffix2 = fileInfo2.completeSuffix();
    qDebug() << "document.txt の completeSuffix():" << completeSuffix2; // 出力: document.txt の completeSuffix(): "txt"

    return a.exec();
}

利点

注意点

  • 単純な最後の拡張子だけが必要な場合には、意図しない結果になる可能性があります。
  • 最初のドットを含むそれ以降のすべての部分を拡張子とみなしたい場合
    QFileInfo::completeSuffix() を使用します。
  • より複雑なパターンに一致する拡張子を抽出したい場合
    正規表現 (QRegularExpression) が強力なツールとなります。
  • 複数のドットがあるファイル名で、最後の拡張子だけが必要な場合
    QString::split() または QString::lastIndexOf()QString::mid() が有効です。
  • 単純な最後の拡張子を取得したい場合
    QFileInfo::suffix() が最も簡潔で推奨されます。