如何从 C++ 中的路径中提取文件名和扩展名

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4430780/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 15:23:43  来源:igfitidea点击:

How can I extract the file name and extension from a path in C++

c++stringfile-io

提问by Octavian

I have a list of files stored in a .login this syntax:

我有一个.log以这种语法存储在 a中的文件列表:

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

I want to extract the name and the extension from this files. Can you give a example of a simple way to do this?

我想从这个文件中提取名称和扩展名。你能举一个简单的方法来做到这一点吗?

回答by Nickolay Merkin

To extract a filename without extension, use boost::filesystem::path::steminstead of ugly std::string::find_last_of(".")

要提取没有扩展名的文件名,请使用 boost::filesystem::path:: stem而不是丑陋的 std::string::find_last_of(".")

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

回答by Yuchen Zhong

For C++17:

对于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"

Reference about filesystem: http://en.cppreference.com/w/cpp/filesystem

关于文件系统的参考:http: //en.cppreference.com/w/cpp/filesystem



As suggested by @RoiDanto, for the output formatting, std::outmay surround the output with quotations, e.g.:

正如@RoiDanto所建议的,对于输出格式,std::out可以用引号将输出括起来,例如:

filename and extension: "file.ext"

You can convert std::filesystem::pathto std::stringby p.filename().string()if that's what you need, e.g.:

您可以转换std::filesystem::pathstd::string通过p.filename().string(),如果这就是你所需要的,例如:

filename and extension: file.ext

回答by Kos

If you want a safe way (i.e. portable between platforms and not putting assumptions on the path), I'd recommend to use boost::filesystem.

如果您想要一种安全的方式(即在平台之间可移植而不是对路径进行假设),我建议使用boost::filesystem.

It would look somehow like this:

它看起来像这样:

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

Then you can extract various data from this path. Here's the documentation of path object.

然后您可以从此路径中提取各种数据。这是路径对象的文档。



BTW: Also remember that in order to use path like

顺便说一句:还要记住,为了使用类似的路径

c:\foto\foto2003\shadow.gif

you need to escape the \in a string literal:

您需要转义\字符串文字中的 :

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

Or use /instead:

或者/改用:

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

This only applies to specifying literal strings in ""quotes, the problem doesn't exist when you load paths from a file.

这仅适用于在""引号中指定文字字符串,从文件加载路径时不存在问题。

回答by Sylvain Defresne

You'll have to read your filenames from the file in std::string. You can use the string extraction operator of std::ostream. Once you have your filename in a std::string, you can use the std::string::find_last_ofmethod to find the last separator.

您必须从std::string. 您可以使用 的字符串提取运算符std::ostream。一旦你的文件名在 a 中std::string,你就可以使用该std::string::find_last_of方法找到最后一个分隔符。

Something like this:

像这样的东西:

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  = "";
    }
}

回答by Nim

Not the code, but here is the idea:

不是代码,但这是一个想法:

  1. Read a std::stringfrom the input stream (std::ifstream), each instance read will be the full path
  2. Do a find_last_ofon the string for the \
  3. Extract a substring from this position to the end, this will now give you the file name
  4. Do a find_last_offor ., and a substring either side will give you name + extension.
  1. std::string从输入流 ( std::ifstream) 中读取 a ,每个实例读取将是完整路径
  2. find_last_of在字符串上做一个\
  3. 从这个位置提取一个子字符串到最后,这将为您提供文件名
  4. 做一个find_last_offor .,两边的子字符串会给你名字+扩展名。

回答by Kemin Zhou

For linux or unix machines, the os has two functions dealing with path and file names. use man 3 basename to get more information about these functions. The advantage of using the system provided functionality is that you don't have to install boost or needing to write your own functions.

对于 linux 或 unix 机器,os 有两个处理路径和文件名的函数。使用 man 3 basename 获取有关这些函数的更多信息。使用系统提供的功能的好处是您不必安装 boost 或需要编写自己的函数。

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

Example code from the man page:

手册页中的示例代码:

   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);

Because of the non-const argument type of the basename() function, it is a little bit non-straight forward using this inside C++ code. Here is a simple example from my code base:

由于 basename() 函数的非常量参数类型,在 C++ 代码中使用 this 有点不直接。这是我的代码库中的一个简单示例:

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;
}

The use of new/delete is not good style. I could have put it into a try/catch block in case something happened between the two calls.

使用 new/delete 不是很好的风格。我可以将它放入 try/catch 块中,以防在两次调用之间发生某些事情。

回答by svanschalkwyk

I also use this snippet to determine the appropriate slash character:

我还使用此代码段来确定适当的斜杠字符:

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

and then replace the slashes with the preferred slash for the OS. Useful if one is constantly deploying between Linux/Windows.

然后用操作系统的首选斜线替换斜线。如果在 Linux/Windows 之间不断部署,则很有用。

回答by Aymen Alsaadi

Try the following trick to extract the file name from path with no extension in c++ with no external libraries in c++ :

尝试使用以下技巧从 c++ 中没有扩展名且 c++ 中没有外部库的路径中提取文件名:

#include <iostream>
#include <string>

using std::string;

string getFileName(const string& s) {
char sep = '/';
#ifdef _WIN32
sep = '\';
#endif
size_t i = s.rfind(sep, s.length());
if (i != string::npos) 
{
string filename = s.substr(i+1, s.length() - i);
size_t lastindex = filename.find_last_of("."); 
string rawname = filename.substr(0, lastindex); 
return(rawname);
}

return("");
}

int main(int argc, char** argv) {

string path = "/home/aymen/hello_world.cpp";
string ss = getFileName(path);
std::cout << "The file name is \"" << ss << "\"\n";
}

回答by Nicholas Mulianto

Nickolay Merkin's and Yuchen Zhong's answers are great, but however from the comments you can see that it is not fully accurate.

Nickolay Merkin 和 Yuchen Zhong 的回答很棒,但是从评论中您可以看出它并不完全准确。

The implicit conversion to std::string when printing will wrap the file name in quotations. The comments aren't accurate either.

打印时隐式转换为 std::string 会将文件名括在引号中。评论也不准确。

path::filename()and path::stem()returns a new path object and path::string()returns a reference to a string. Thus something like std::cout << file_path.filename().string() << "\n"might cause problems with dangling reference since the string that the reference points to might have been destroyed.

path::filename()path::stem()返回一个新的路径对象并path::string()返回对字符串的引用。因此,类似的东西std::cout << file_path.filename().string() << "\n"可能会导致悬空引用出现问题,因为引用指向的字符串可能已被破坏。