2010-12-13 184 views
43

的路径提取的文件名和扩展名我都存储在.log在这句法的文件列表:我怎样才能在C++

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

我想提取的名称,并从该文件的扩展名。你能举一个简单的方法来做这个例子吗?

回答

126

要提取的文件名不带扩展名,使用boost ::文件系统::路径:: ,而不是丑陋的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 
+0

同意。最简洁地回答问题。 – AndyUK 2014-05-28 12:43:18

+7

实际上,p.filename()是类型路径,并且在隐式转换时将被引号包围,因此您将得到: 文件名和扩展名:“file.ext” 您可能想要p.filename()。 string()代替。 – 2016-02-18 19:54:27

+1

使用C++ 14/C++ 17,你可以使用'std :: experimental :: filesystem'和'std :: filesystem'。见下面的Yuchen Zhong的帖子。 – 2017-04-12 14:15:44

3

不是代码,但这里的理念是:

  1. 从输入流(std::ifstream),每个实例读会的完整路径阅读std::string
  2. 的字符串为做一个find_last_of\
  3. 提取从这个位置到最后一个子,现在这会给你的文件名
  4. 做一个find_last_of.,和一个子两侧会给你名字+扩展名。
+0

+1仅用于提供帮助而不提供代码。 – razlebe 2010-12-13 16:12:12

+0

而且-1不能携带:) – Kos 2010-12-13 16:12:44

+0

为什么要投票?如果我说的话有什么问题,请告诉我,我会解决的! – Nim 2010-12-13 16:13:24

19

如果你想要一个安全的方式(即平台之间的便携式,而不是假设的道路),我建议使用boost::filesystem

它看起来在某种程度上是这样的:

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

然后你可以从这个路径提取各种数据。 Here's the documentation of path object.


BTW:还记得,为了使用路径喜欢

c:\foto\foto2003\shadow.gif 

你一定要逃逸一个字符串的\

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

或者使用/代替:

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

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

+2

+1肯定要走的路。主站点上的示例提供了搜索目录的方法:使用path.extension()方法搜索日志(请参阅http://www.boost.org/doc/libs/1_36_0/libs/filesystem/doc/index .htm) – Tom 2010-12-13 16:18:43

+0

事实上,在大多数情况下,这是要走的路,但它涉及在某些情况下添加对外部库的不良依赖。如果你只想使用C++标准提供的东西,我建议你看一下C++的正则表达式,在那里你可以定义一个正则表达式来做你想做的事情(互联网上有很多例子)。优点 - 由于一些额外的依赖关系,没有开销。然而,这也让一个问题开放 - 是否需要多平台?无论您使用的是Windows还是Linux,Boost都会照顾路径风格。使用正则表达式你必须自己做。 – rbaleksandar 2014-07-11 20:13:00

13

您必须从std::string中的文件中读取您的文件名。您可以使用std::ostream的字符串提取操作符。一旦你的文件名为std::string,你可以使用std::string::find_last_of方法找到最后一个分隔符。

事情是这样的:

​​
+0

不想成为自作聪明,但它应该是path.substr而不是path.substring,对吧? – 2012-02-23 09:10:13

0

我也使用这个片段以确定适当的斜杠字符:

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

,然后与用于OS优选斜线取代斜线有用的,如果一台Linux之间不断部署/ 。窗户

6

对于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::pathstd::string如果这就是你所需要的,例如:

filename and extension: file.ext 
+0

嗨@RoiDanton,感谢编辑!我再次检查了引用链接中的示例代码,似乎没有必要将返回类型从'std :: filesystem :: path'转换为'std :: string'以便能够使用'的std :: cout'。 http://en.cppreference.com/w/cpp/filesystem/path/filename但是,如果您认为不然,请随时评论或编辑帖子。 – 2017-04-12 14:39:27

+0

这是真的,'std :: cout'可以依靠隐式转换。然而,由于'std :: cout'后面的注释表示file.ext和file,无论是'.string()'都必须添加到注释中,否则它们应该是“file.ext”和“file”。使用Visual C++确实没有区别(即使没有'string()'输出也没有引号),但对于gcc 6.1,如果忽略'.string()',输出将带有引号。见http://coliru.stacked-crooked.com/view?id=a55ea60bbd36a8a3 – 2017-04-12 14:56:44

+0

@RoiDanton,嘿,这是有趣的见解。我会再次更新这篇文章。感谢分享! – 2017-04-12 15:21:02

0

对于Linux或UNIX机器,操作系统有一个处理的路径和文件名的两种功能。使用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); 

由于非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不是很好的样式。如果两次调用之间发生任何事情,我可以将它放入try/catch 区块。