web-dev-qa-db-ja.com

C ++のパスからファイル名と拡張子を抽出するにはどうすればよいですか

この構文の.logに保存されているファイルのリストがあります。

c:\foto\foto2003\shadow.gif
D:\etc\mom.jpg

このファイルから名前と拡張子を抽出したい。これを行う簡単な方法の例を挙げていただけますか?

63
Octavian

拡張子なしでファイル名を抽出するには、boostいstd :: string :: find_last_of( "。")の代わりにboost :: filesystem :: path :: stemを使用します

boost::filesystem::path p("c:/dir/dir/file.ext");
std::cout << "filename and extension : " << p.filename() << std::endl; // file.ext
std::cout << "filename only          : " << p.stem() << std::endl;     // file
156
Nickolay Merkin

安全な方法が必要な場合(つまり、プラットフォーム間で移植可能で、パスに仮定を置かない)、boost::filesystemを使用することをお勧めします。

次のようになります。

boost::filesystem::path my_path( filename );

その後、このパスからさまざまなデータを抽出できます。 パスオブジェクトのドキュメントを次に示します。


ところで:また、パスを使用するために

c:\foto\foto2003\shadow.gif

文字列リテラルで\をエスケープする必要があります。

const char* filename = "c:\\foto\\foto2003\\shadow.gif";

または、代わりに/を使用します。

const char* filename = "c:/foto/foto2003/shadow.gif";

これは、""引用符でリテラル文字列を指定する場合にのみ適用されます。ファイルからパスをロードする場合、問題は存在しません。

20
Kos

std::stringのファイルからファイル名を読み取る必要があります。 std::ostreamの文字列抽出演算子を使用できます。 std::stringにファイル名を入れたら、std::string::find_last_ofメソッドを使用して最後の区切り文字を見つけることができます。

このようなもの:

std::ifstream input("file.log");
while (input)
{
    std::string path;
    input >> path;

    size_t sep = path.find_last_of("\\/");
    if (sep != std::string::npos)
        path = path.substr(sep + 1, path.size() - sep - 1);

    size_t dot = path.find_last_of(".");
    if (dot != std::string::npos)
    {
        std::string name = path.substr(0, dot);
        std::string ext  = path.substr(dot, path.size() - dot);
    }
    else
    {
        std::string name = path;
        std::string ext  = "";
    }
}
15

C++ 17の場合:

_#include <filesystem>

std::filesystem::path p("c:/dir/dir/file.ext");
std::cout << "filename and extension: " << p.filename() << std::endl; // "file.ext"
std::cout << "filename only: " << p.stem() << std::endl;              // "file"
_

ファイルシステムに関するリファレンス: http://en.cppreference.com/w/cpp/filesystem


@ RoiDantoで示唆されているように、出力の書式設定では、_std::out_が出力を引用符で囲む場合があります。例:

_filename and extension: "file.ext"
_

必要であれば、p.filename().string()で_std::filesystem::path_を_std::string_に変換できます。例:

_filename and extension: file.ext
_
14
Yuchen Zhong

コードではなく、ここにアイデアがあります:

  1. 入力ストリーム(std::string)からstd::ifstreamを読み取ります。読み取られた各インスタンスはフルパスになります
  2. find_last_ofの文字列に対して\を実行します
  3. この位置から最後まで部分文字列を抽出すると、ファイル名が表示されます
  4. find_last_ofに対して.を実行すると、いずれかの側のサブストリングに名前と拡張子が付けられます。
3
Nim

Nickolay MerkinとYuchen Zhongの回答は素晴らしいですが、コメントからは完全に正確ではないことがわかります。

印刷時のstd :: stringへの暗黙的な変換は、ファイル名を引用符で囲みます。コメントも正確ではありません。

path::filename()およびpath::stem()は新しいパスオブジェクトを返し、path::string()は文字列への参照を返します。したがって、std::cout << file_path.filename().string() << "\n"のようなものは、参照が指す文字列が破壊された可能性があるため、参照のダングリングで問題を引き起こす可能性があります。

0

LinuxまたはUNIXマシンの場合、osにはパスとファイル名を扱う2つの関数があります。これらの関数に関する詳細情報を取得するには、man 3 basenameを使用してください。システムが提供する機能を使用する利点は、boostをインストールしたり、独自の機能を作成したりする必要がないことです。

#include <libgen.h>
       char *dirname(char *path);
       char *basename(char *path);

マニュアルページのサンプルコード:

   char *dirc, *basec, *bname, *dname;
           char *path = "/etc/passwd";

           dirc = strdup(path);
           basec = strdup(path);
           dname = dirname(dirc);
           bname = basename(basec);
           printf("dirname=%s, basename=%s\n", dname, bname);

Basename()関数のconst以外の引数タイプのため、C++コード内でこれを使用すると、少し非直線的です。コードベースの簡単な例を次に示します。

string getFileStem(const string& filePath) const {
   char* buff = new char[filePath.size()+1];
   strcpy(buff, filePath.c_str());
   string tmp = string(basename(buff));
   string::size_type i = tmp.rfind('.');
   if (i != string::npos) {
      tmp = tmp.substr(0,i);
   }
   delete[] buff;
   return tmp;
}

New/deleteの使用は良いスタイルではありません。 2つの呼び出しの間に何かが起こった場合に備えて、try/catchブロックに入れることもできます。

0
Kemin Zhou

また、このスニペットを使用して適切なスラッシュ文字を決定します。

boost::filesystem::path slash("/");
    boost::filesystem::path::string_type preferredSlash = slash.make_preferred().native();

そして、スラッシュをOSの優先スラッシュに置き換えます。 Linux/Windows間で絶えず展開している場合に役立ちます。

0
svanschalkwyk