我使用.log
以下语法存储了一个文件列表:
c:\foto\foto2003\shadow.gif
D:\etc\mom.jpg
我想从该文件中提取名称和扩展名。您能否举一个简单的例子来做到这一点?
Answers:
要提取不带扩展名的文件名,使用升压::文件系统::路径::干的,而不是丑陋的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
std::experimental::filesystem
resp std::filesystem
。请参阅下面来自Yuchen Zhong的帖子。
对于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"
如果需要的话,可以转换std::filesystem::path
为std::string
by p.filename().string()
,例如:
filename and extension: file.ext
std::filesystem::path
到std::string
为了能够使用std::cout
。zh-cn.cppreference.com/w/cpp/filesystem/path/filename但是,如果您有其他看法,请随时发表评论或编辑帖子。
std::cout
可以依靠隐式转换。但是,由于std::cout
说file.ext和file之后的注释,.string()
必须添加到注释中,或者它们应该是“ file.ext”和“ file”。使用Visual C ++确实没有区别(即使没有string()
输出也没有引号),但是对于gcc 6.1,如果.string()
省略了输出,则带有引号。参见coliru.stacked-crooked.com/view?id=a55ea60bbd36a8a3
如果您想要一种安全的方法(即在平台之间可移植并且不对路径进行假设),建议使用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";
这仅适用于在""
引号中指定文字字符串,从文件加载路径时不存在此问题。
您必须从中的文件读取文件名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 = "";
}
}
不是代码,而是这里的想法:
std::string
从输入流(std::ifstream
)中读取一个,每个读取的实例将是完整路径find_last_of
对字符串做一个\
find_last_of
for .
,任一侧的子字符串都将为您提供名称+扩展名。/
。而且我什至不知道路径规范中是否存在更多警告,所以我的想法很简单-如果有一个很好的库可以满足我的需求,那么我应该使用它,因为它可能比我能更好地实现我的目标。;)
boost::insects::disperser<T>
通用模板吗?:)
我还使用此代码段确定适当的斜杠字符:
boost::filesystem::path slash("/");
boost::filesystem::path::string_type preferredSlash = slash.make_preferred().native();
然后将斜杠替换为操作系统的首选斜杠。如果人们经常在Linux / Windows之间进行部署,则很有用。
对于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);
由于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并不是很好的样式。我可以将其放入try / catch块中,以防两次调用之间发生某些情况。
尝试以下技巧,从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";
}
尼古拉·默金(Nickolay Merkin)和钟雨辰(Yuchen Zhong)的回答很不错,但是从评论中您可以看到它并不完全准确。
打印时隐式转换为std :: string会将文件名括在引号中。评论也不正确。
path::filename()
并path::stem()
返回一个新的路径对象,并path::string()
返回一个对字符串的引用。因此,类似的内容std::cout << file_path.filename().string() << "\n"
可能会导致悬挂引用出现问题,因为引用所指向的字符串可能已被破坏。