从path获取文件名
从path获取文件名最简单的方法是什么?
string filename = "C:\\MyDirectory\\MyFile.bat"
在这个例子中,我应该得到“MyFile”。 没有扩展。
_splitpath应该做你需要的。 你当然可以手动做,但是_splitpath
处理所有的特殊情况。
编辑:
正如BillHoag提到的那样,推荐在可用时使用_splitpath
更安全的版本_splitpath
。
或者,如果你想要的东西便携式,你可以做这样的事情
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;
最简单的解决scheme是使用诸如boost::filesystem
类的东西。 如果由于某种原因,这不是一个选项…
正确执行此操作需要一些与系统相关的代码:在Windows下, '\\'
或'/'
可以是path分隔符; 在Unix下,只有'/'
可以工作,而在其他系统下,谁知道。 显而易见的解决scheme是这样的:
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的事实。 (如果唯一的'.'
是文件名的第一个字符,我认为你应该返回完整的文件名,这将需要一些额外的代码来捕捉特殊情况。
可能的解决scheme:
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); }
该任务非常简单,因为基本文件名只是从文件夹的最后一个分隔符开始的string的一部分:
std::string base_filename = path.substr(path.find_last_of("/\\") + 1)
如果扩展名被删除,唯一要做的就是find最后一个.
并采取一个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
…)
模板的缺点是需要指定模板参数,如果一个const char *
被传递给函数。
所以你可以:
A)只使用std::string
而不是模板代码
std::string base_name(std::string const & path) { return path.substr(path.find_last_of("/\\") + 1); }
B)使用std::string
提供包装函数(作为可能被内联/优化的中介)
inline std::string string_base_name(std::string const & path) { return base_name(path); }
C)使用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
您也可以使用shellpathAPI PathFindFileName,PathRemoveExtension。 可能比_splitpath对于这个特定的问题更糟,但是这些API对于各种path分析工作非常有用,并且它们将UNCpath,正斜杠和其他奇怪的东西考虑在内。
wstring filename = L"C:\\MyDirectory\\MyFile.bat"; wchar_t* filepart = PathFindFileName(filename.c_str()); PathRemoveExtension(filepart);
http://msdn.microsoft.com/en-us/library/windows/desktop/bb773589(v=vs.85).aspx
缺点是你必须链接到shlwapi.lib,但我不确定为什么这是一个缺点。
如果你可以使用提升,
#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();
这就是全部。
我build议你使用boost库。 当您使用C ++时,Boost为您提供了许多便利。 它几乎支持所有的平台。 如果你使用的是Ubuntu,你可以通过一行安装boost库sudo apt-get install libboost-all-dev
(参考如何在Ubuntu上安装boost )
从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
function:
#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); }
testing:
#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"); }
我会做…
从string的末尾向后search,直到find第一个反斜杠/正斜杠。
然后从string的末尾向后search,直到find第一个点(。)
然后你有文件名的开始和结束。
Simples …
C ++ 11变体(由James Kanze的版本启发),具有统一初始化和匿名内联lambda。
std::string basename(const std::string& pathname) { return {std::find_if(pathname.rbegin(), pathname.rend(), [](char c) { return c == '/'; }).base(), pathname.end()}; }
它不会删除文件扩展名。
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; }
variablesm_szFileName包含fileName。
这也应该工作:
// 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等来操纵文件,文件名和目录。 当然,这也是跨平台的。
这是真正终于为我工作的唯一的事情:
#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);
几乎是Skrymslibuild议的,但不适用于wchar_t *,VS Enterprise 2015
_splitpath也起作用,但是我不喜欢猜测我需要多less个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需要包含任何内容。 这两种解决scheme都不需要外部库(如boost)。
另外,也许值得看看正则expression式。 你可以在这里find很多信息: http : //www.regular-expressions.info/tutorial.html
不要使用_splitpath()
和_wsplitpath()
。 他们不安全,他们已经过时了!
相反,使用他们的安全版本,即_splitpath_s()
和_wsplitpath_s()
很长一段时间,我正在寻找一个能够正确分解文件path的function。 对我来说,这个代码对于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\bc] 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: ''
我希望这也可以帮助你:)