从路径获取文件名的最简单方法是什么?
string filename = "C:\\MyDirectory\\MyFile.bat"
在这个例子中,我应该得到“ MyFile”。没有扩展名。
从路径获取文件名的最简单方法是什么?
string filename = "C:\\MyDirectory\\MyFile.bat"
在这个例子中,我应该得到“ MyFile”。没有扩展名。
Answers:
_splitpath应该可以满足您的需求。您当然可以手动执行,但也可以_splitpath
处理所有特殊情况。
编辑:
作为BillHoag提到,建议使用更安全版本_splitpath
称为_splitpath_s时可用。
或者,如果您想要便携式的东西,可以做这样的事情
std::vector<std::string> splitpath(
const std::string& str
, const std::set<char> delimiters)
{
std::vector<std::string> result;
char const* pch = str.c_str();
char const* start = pch;
for(; *pch; ++pch)
{
if (delimiters.find(*pch) != delimiters.end())
{
if (start != pch)
{
std::string str(start, pch);
result.push_back(str);
}
else
{
result.push_back("");
}
start = pch + 1;
}
}
result.push_back(start);
return result;
}
...
std::set<char> delims{'\\'};
std::vector<std::string> path = splitpath("C:\\MyDirectory\\MyFile.bat", delims);
cout << path.back() << endl;
_splitpath
我的机器上没有任何附件。
<stdlib.h>
。至于可移植性,也许您可以列举“完美的便携式解决方案”的一些例子?
<stdlib.h>
。而最明显的便携式解决方案是boost::filesystem
。
_splitpath
在stdlib.h
你的VS的副本?然后,您可能需要进行VS的修复安装。
可能的解决方案:
string filename = "C:\\MyDirectory\\MyFile.bat";
// Remove directory if present.
// Do this before extension removal incase directory has a period character.
const size_t last_slash_idx = filename.find_last_of("\\/");
if (std::string::npos != last_slash_idx)
{
filename.erase(0, last_slash_idx + 1);
}
// Remove extension if present.
const size_t period_idx = filename.rfind('.');
if (std::string::npos != period_idx)
{
filename.erase(period_idx);
}
任务非常简单,因为基本文件名只是字符串的一部分,从文件夹的最后一个分隔符开始:
std::string base_filename = path.substr(path.find_last_of("/\\") + 1)
如果也要删除扩展名,那么唯一要做的就是找到最后一个.
,然后substr
到此处
std::string::size_type const p(base_filename.find_last_of('.'));
std::string file_without_extension = base_filename.substr(0, p);
也许应该进行检查以处理仅由扩展名组成的文件(即.bashrc
...)
如果将其拆分为单独的功能,则可以灵活地重用单个任务:
template<class T>
T base_name(T const & path, T const & delims = "/\\")
{
return path.substr(path.find_last_of(delims) + 1);
}
template<class T>
T remove_extension(T const & filename)
{
typename T::size_type const p(filename.find_last_of('.'));
return p > 0 && p != T::npos ? filename.substr(0, p) : filename;
}
该代码已模板化,可以与其他std::basic_string
实例(即std::string
&std::wstring
...)一起使用
如果将aconst char *
传递给函数,则模板的缺点是必须指定模板参数。
因此,您可以:
std::string
而不是模板代码std::string base_name(std::string const & path)
{
return path.substr(path.find_last_of("/\\") + 1);
}
std::string
(作为可能会被内联/优化的中间体)inline std::string string_base_name(std::string const & path)
{
return base_name(path);
}
const char *
。std::string base = base_name<std::string>("some/path/file.ext");
std::string filepath = "C:\\MyDirectory\\MyFile.bat";
std::cout << remove_extension(base_name(filepath)) << std::endl;
版画
MyFile
base_name
请先申请。)
最简单的解决方案是使用boost::filesystem
。如果由于某种原因这不是一个选择...
正确执行此操作将需要一些与系统相关的代码:在Windows中,可以为'\\'
或'/'
可以是路径分隔符;在Unix下,只有'/'
在其他系统下才有效,谁知道呢。显而易见的解决方案是这样的:
std::string
basename( std::string const& pathname )
{
return std::string(
std::find_if( pathname.rbegin(), pathname.rend(),
MatchPathSeparator() ).base(),
pathname.end() );
}
与MatchPathSeparator
在一个依赖于系统的标头,如任一所限定:
struct MatchPathSeparator
{
bool operator()( char ch ) const
{
return ch == '/';
}
};
对于Unix,或:
struct MatchPathSeparator
{
bool operator()( char ch ) const
{
return ch == '\\' || ch == '/';
}
};
Windows(或其他未知系统仍然有所不同)。
编辑:我错过了一个事实,他也想抑制这种扩张。为此,更多的相同:
std::string
removeExtension( std::string const& filename )
{
std::string::const_reverse_iterator
pivot
= std::find( filename.rbegin(), filename.rend(), '.' );
return pivot == filename.rend()
? filename
: std::string( filename.begin(), pivot.base() - 1 );
}
代码稍微复杂一点,因为在这种情况下,反向迭代器的基础位于我们要剪切的位置的错误一侧。(请记住,反向迭代器的基址位于该迭代器所指向的字符之后。)甚至这还有一点可疑:例如,我不喜欢它可以返回一个空字符串的事实。(如果唯一的'.'
是文件名的第一个字符,我认为您应该返回完整的文件名。这将需要一些额外的代码来捕获特殊情况。)
string::find_last_of
而不是操纵反向迭代器怎么样?
string
,因此无论如何都必须学习它们。并且已经学习了它们,因此没有理由去烦恼所有to肿的接口std::string
。
您还可以使用外壳程序路径API PathFindFileName,PathRemoveExtension。对于这个特定问题,它可能比_splitpath更糟糕,但是这些API对于各种路径解析作业都非常有用,并且它们考虑了UNC路径,正斜杠和其他怪异的东西。
wstring filename = L"C:\\MyDirectory\\MyFile.bat";
wchar_t* filepart = PathFindFileName(filename.c_str());
PathRemoveExtension(filepart);
http://msdn.microsoft.com/zh-CN/library/windows/desktop/bb773589(v=vs.85).aspx
缺点是您必须链接到shlwapi.lib,但是我不太确定为什么这是缺点。
如果可以使用boost,
#include <boost/filesystem.hpp>
path p("C:\\MyDirectory\\MyFile.bat");
string basename = p.filename().string();
//or
//string basename = path("C:\\MyDirectory\\MyFile.bat").filename().string();
这就是全部。
我建议您使用Boost库。使用C ++时,Boost给您带来许多便利。它支持几乎所有平台。如果您使用Ubuntu,则只能通过一行安装boost库sudo apt-get install libboost-all-dev
(请参阅如何在Ubuntu上安装boost?)
C ++ 17中最简单的方法是:
对扩展名和不扩展名使用#include <filesystem>
和filename()
表示文件stem()
名。
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
string filename = "C:\\MyDirectory\\MyFile.bat";
std::cout << fs::path(filename).filename() << '\n'
<< fs::path(filename).stem() << '\n'
<< fs::path("/foo/bar.txt").filename() << '\n'
<< fs::path("/foo/bar.txt").stem() << '\n'
<< fs::path("/foo/.bar").filename() << '\n'
<< fs::path("/foo/bar/").filename() << '\n'
<< fs::path("/foo/.").filename() << '\n'
<< fs::path("/foo/..").filename() << '\n'
<< fs::path(".").filename() << '\n'
<< fs::path("..").filename() << '\n'
<< fs::path("/").filename() << '\n';
}
输出:
MyFile.bat
MyFile
"bar.txt"
".bar"
"."
"."
".."
"."
".."
"/"
参考:cppreference
功能:
#include <string>
std::string
basename(const std::string &filename)
{
if (filename.empty()) {
return {};
}
auto len = filename.length();
auto index = filename.find_last_of("/\\");
if (index == std::string::npos) {
return filename;
}
if (index + 1 >= len) {
len--;
index = filename.substr(0, len).find_last_of("/\\");
if (len == 0) {
return filename;
}
if (index == 0) {
return filename.substr(1, len - 1);
}
if (index == std::string::npos) {
return filename.substr(0, len);
}
return filename.substr(index + 1, len - index - 1);
}
return filename.substr(index + 1, len - index);
}
测试:
#define CATCH_CONFIG_MAIN
#include <catch/catch.hpp>
TEST_CASE("basename")
{
CHECK(basename("") == "");
CHECK(basename("no_path") == "no_path");
CHECK(basename("with.ext") == "with.ext");
CHECK(basename("/no_filename/") == "no_filename");
CHECK(basename("no_filename/") == "no_filename");
CHECK(basename("/no/filename/") == "filename");
CHECK(basename("/absolute/file.ext") == "file.ext");
CHECK(basename("../relative/file.ext") == "file.ext");
CHECK(basename("/") == "/");
CHECK(basename("c:\\windows\\path.ext") == "path.ext");
CHECK(basename("c:\\windows\\no_filename\\") == "no_filename");
}
从C ++ Docs- string :: find_last_of
#include <iostream> // std::cout
#include <string> // std::string
void SplitFilename (const std::string& str) {
std::cout << "Splitting: " << str << '\n';
unsigned found = str.find_last_of("/\\");
std::cout << " path: " << str.substr(0,found) << '\n';
std::cout << " file: " << str.substr(found+1) << '\n';
}
int main () {
std::string str1 ("/usr/bin/man");
std::string str2 ("c:\\windows\\winhelp.exe");
SplitFilename (str1);
SplitFilename (str2);
return 0;
}
输出:
Splitting: /usr/bin/man
path: /usr/bin
file: man
Splitting: c:\windows\winhelp.exe
path: c:\windows
file: winhelp.exe
find_last_of
返回的string::npos
结果。
string::npos
由于这和string::substr
实现的方式,不需要进行检查。a)string::npos
作为“长度”传递=>substr
具有记录所有读取直到结束的行为。b)substr
被赋予“ string::npos + 1
”且没有长度:string::npos
记录为具有值-1
,因此计算结果为0
=>字符串的开始,并且长度的默认值substr
是npos
=>也可以“仅用于文件名” cplusplus.com/reference / string / string / substr cplusplus.com/reference/string/string/npos
具有统一初始化和匿名内联lambda的C ++ 11变体(受James Kanze版本启发)。
std::string basename(const std::string& pathname)
{
return {std::find_if(pathname.rbegin(), pathname.rend(),
[](char c) { return c == '/'; }).base(),
pathname.end()};
}
但是它不会删除文件扩展名。
return c == '/' || c == '\\';
使其在Windows上运行
if (pathname.size() == 0) return "."; auto iter = pathname.rbegin(); auto rend = pathname.rend(); while (iter != rend && *iter == '/') ++iter; if (iter == rend) /* pathname has only path separators */ return "/"; pathname = std::string(pathname.begin(), iter.base());
该boost
filesystem
库也可以作为experimental/filesystem
库使用,并已合并到C ++ 17的ISO C ++中。您可以像这样使用它:
#include <iostream>
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
int main () {
std::cout << fs::path("/foo/bar.txt").filename() << '\n'
}
输出:
"bar.txt"
它也适用于std::string
对象。
这是唯一真正对我有用的东西:
#include "Shlwapi.h"
CString some_string = "c:\\path\\hello.txt";
LPCSTR file_path = some_string.GetString();
LPCSTR filepart_c = PathFindFileName(file_path);
LPSTR filepart = LPSTR(filepart_c);
PathRemoveExtension(filepart);
Skrymsli建议的内容几乎与VS Enterprise 2015的wchar_t *不兼容
_splitpath也可以正常工作,但是我不希望猜测我需要多少个char [?]字符;我猜有些人可能需要此控件。
CString c_model_name = "c:\\path\\hello.txt";
char drive[200];
char dir[200];
char name[200];
char ext[200];
_splitpath(c_model_name, drive, dir, name, ext);
我认为_splitpath不需要任何包含内容。这些解决方案均不需要外部库(例如boost)。
我会...
从字符串末尾开始向后搜索,直到找到第一个反斜杠/正斜杠。
然后从字符串末尾再次向后搜索,直到找到第一个点(。)。
然后,您将拥有文件名的开头和结尾。
简单...
'\\'
为路径分隔符的系统也使用'/'
,因此您需要匹配两者。)而且我不确定您会期待什么。
my.source.cpp
被编译到my.source.obj
,例如(扩展.cpp
替换为.obj
)。
m_szFilePath.MakeLower();
CFileFind finder;
DWORD buffSize = MAX_PATH;
char longPath[MAX_PATH];
DWORD result = GetLongPathName(m_szFilePath, longPath, MAX_PATH );
if( result == 0)
{
m_bExists = FALSE;
return;
}
m_szFilePath = CString(longPath);
m_szFilePath.Replace("/","\\");
m_szFilePath.Trim();
//check if it does not ends in \ => remove it
int length = m_szFilePath.GetLength();
if( length > 0 && m_szFilePath[length - 1] == '\\' )
{
m_szFilePath.Truncate( length - 1 );
}
BOOL bWorking = finder.FindFile(this->m_szFilePath);
if(bWorking){
bWorking = finder.FindNextFile();
finder.GetCreationTime(this->m_CreationTime);
m_szFilePath = finder.GetFilePath();
m_szFileName = finder.GetFileName();
this->m_szFileExtension = this->GetExtension( m_szFileName );
m_szFileTitle = finder.GetFileTitle();
m_szFileURL = finder.GetFileURL();
finder.GetLastAccessTime(this->m_LastAccesTime);
finder.GetLastWriteTime(this->m_LastWriteTime);
m_ulFileSize = static_cast<unsigned long>(finder.GetLength());
m_szRootDirectory = finder.GetRoot();
m_bIsArchive = finder.IsArchived();
m_bIsCompressed = finder.IsCompressed();
m_bIsDirectory = finder.IsDirectory();
m_bIsHidden = finder.IsHidden();
m_bIsNormal = finder.IsNormal();
m_bIsReadOnly = finder.IsReadOnly();
m_bIsSystem = finder.IsSystem();
m_bIsTemporary = finder.IsTemporary();
m_bExists = TRUE;
finder.Close();
}else{
m_bExists = FALSE;
}
变量m_szFileName包含文件名。
boost::filesystem::path( path ).filename()
。
不要使用_splitpath()
和_wsplitpath()
。它们不安全,并且已过时!
而是使用其安全版本,即_splitpath_s()
和_wsplitpath_s()
这也应该工作:
// strPath = "C:\\Dir\\File.bat" for example
std::string getFileName(const std::string& strPath)
{
size_t iLastSeparator = 0;
return strPath.substr((iLastSeparator = strPath.find_last_of("\\")) != std::string::npos ? iLastSeparator + 1 : 0, strPath.size() - strPath.find_last_of("."));
}
如果可以使用它,Qt将提供QString(带有分割,修剪等),QFile,QPath,QFileInfo等来操纵文件,文件名和目录。当然,它也跨界。
getFilename
或类似的东西中)。
长期以来,我一直在寻找一种能够正确分解文件路径的函数。对我来说,这段代码可以在Linux和Windows上完美运行。
void decomposePath(const char *filePath, char *fileDir, char *fileName, char *fileExt)
{
#if defined _WIN32
const char *lastSeparator = strrchr(filePath, '\\');
#else
const char *lastSeparator = strrchr(filePath, '/');
#endif
const char *lastDot = strrchr(filePath, '.');
const char *endOfPath = filePath + strlen(filePath);
const char *startOfName = lastSeparator ? lastSeparator + 1 : filePath;
const char *startOfExt = lastDot > startOfName ? lastDot : endOfPath;
if(fileDir)
_snprintf(fileDir, MAX_PATH, "%.*s", startOfName - filePath, filePath);
if(fileName)
_snprintf(fileName, MAX_PATH, "%.*s", startOfExt - startOfName, startOfName);
if(fileExt)
_snprintf(fileExt, MAX_PATH, "%s", startOfExt);
}
结果示例如下:
[]
fileDir: ''
fileName: ''
fileExt: ''
[.htaccess]
fileDir: ''
fileName: '.htaccess'
fileExt: ''
[a.exe]
fileDir: ''
fileName: 'a'
fileExt: '.exe'
[a\b.c]
fileDir: 'a\'
fileName: 'b'
fileExt: '.c'
[git-archive]
fileDir: ''
fileName: 'git-archive'
fileExt: ''
[git-archive.exe]
fileDir: ''
fileName: 'git-archive'
fileExt: '.exe'
[D:\Git\mingw64\libexec\git-core\.htaccess]
fileDir: 'D:\Git\mingw64\libexec\git-core\'
fileName: '.htaccess'
fileExt: ''
[D:\Git\mingw64\libexec\git-core\a.exe]
fileDir: 'D:\Git\mingw64\libexec\git-core\'
fileName: 'a'
fileExt: '.exe'
[D:\Git\mingw64\libexec\git-core\git-archive.exe]
fileDir: 'D:\Git\mingw64\libexec\git-core\'
fileName: 'git-archive'
fileExt: '.exe'
[D:\Git\mingw64\libexec\git.core\git-archive.exe]
fileDir: 'D:\Git\mingw64\libexec\git.core\'
fileName: 'git-archive'
fileExt: '.exe'
[D:\Git\mingw64\libexec\git-core\git-archiveexe]
fileDir: 'D:\Git\mingw64\libexec\git-core\'
fileName: 'git-archiveexe'
fileExt: ''
[D:\Git\mingw64\libexec\git.core\git-archiveexe]
fileDir: 'D:\Git\mingw64\libexec\git.core\'
fileName: 'git-archiveexe'
fileExt: ''
希望对您有所帮助:)