はじめに
C++でファイルパスの文字列を扱う際、「document.txt
」というパスから、拡張子 .txt
を除いた「document
」の部分だけを抜き出したい、という場面は頻繁にあります。
従来は、文字列検索で最後の .
を探し、それより前の部分文字列を取得する、といった手動での処理が必要でした。
C++17で導入された <filesystem>
ライブラリは、このようなパスの構成要素を解析・操作するための、非常に強力で便利なツールセットを提供します。その中の一つ、.stem()
メンバ関数を使えば、この処理を一行で、安全かつ直感的に行うことができます。
【前提】C++17とは?
C++17は、2017年に正式化されたC++言語の規格です。<filesystem>
ライブラリはこのC++17で導入されたため、利用するにはC++17に対応したコンパイラと、適切なコンパイラ設定(および、一部の環境ではリンカ設定)が必要になります。
.stem()
を使ったサンプルコード
このコードは、いくつかの異なる形式のパス文字列に対して .stem()
を呼び出し、その挙動を確認します。
完成コード
#include <iostream>
#include <filesystem> // filesystemライブラリ
#include <string>
// filesystem名前空間のエイリアス
namespace fs = std::filesystem;
int main() {
// 1. 通常のファイル名
fs::path p1("report.docx");
std::cout << p1 << " -> .stem() -> " << p1.stem() << std::endl;
// 2. 拡張子がないファイル名
fs::path p2("myfile");
std::cout << p2 << " -> .stem() -> " << p2.stem() << std::endl;
// 3. ドットが複数あるファイル名
fs::path p3("archive.tar.gz");
std::cout << p3 << " -> .stem() -> " << p3.stem() << std::endl;
// 4. フルパス
fs::path p4("/home/user/document.pdf");
std::cout << p4 << " -> .stem() -> " << p4.stem() << std::endl;
// 5. ディレクトリパス
fs::path p5("/home/user/");
std::cout << p5 << " -> .stem() -> " << p5.stem() << std::endl;
return 0;
}
実行結果
"report.docx" -> .stem() -> "report"
"myfile" -> .stem() -> "myfile"
"archive.tar.gz" -> .stem() -> "archive.tar"
"/home/user/document.pdf" -> .stem() -> "document"
"/home/user/" -> .stem() -> ""
コードの解説
fs::path p1("report.docx");
std::filesystem::path
は、ファイルシステムのパスを表現し、操作するためのクラスです。文字列から path
オブジェクトを構築します。
p1.stem()
- 機能:
path
オブジェクトが保持するパスのファイル名部分から、最後の拡張子とその前の.
を取り除いたものを返します。 - 戻り値:
path
オブジェクト。std::cout
などで表示する際は、暗黙的に文字列に変換されます。 - 挙動の詳細:
"report.docx"
: ファイル名report.docx
から最後の拡張子.docx
を除いた"report"
を返します。"archive.tar.gz"
: ファイル名archive.tar.gz
から、最後の拡張子.gz
だけを除いた"archive.tar"
を返します。"/home/user/document.pdf"
: パス全体からファイル名部分document.pdf
を認識し、そのstem
である"document"
を返します。"/home/user/"
: パスにファイル名部分が含まれない(ディレクトリで終わっている)ため、stem
は空文字列""
を返します。
まとめ
今回は、C++17の <filesystem>
ライブラリを使って、パスから拡張子を除いたファイル名部分を取得する .stem()
メソッドについて解説しました。
<filesystem>
ヘッダーをインクルードする。std::filesystem::path
オブジェクトを作成する。.stem()
メンバ関数を呼び出す。
.stem()
は、パス文字列を手動で解析する手間を省き、様々な形式のパスに対して一貫した、安全な方法でファイル名の本体を取得できる、非常に便利なツールです。