如何从C ++中的string获得文件扩展名
给定一个string"filename.conf"
,如何validation扩展部分?
我需要一个跨平台的解决scheme。
你必须确保你照顾的文件名多一点。 例如: c:\.directoryname\file.name.with.too.many.dots.ext
将不会被strchr
或find.
正确处理find.
我最喜欢的是具有扩展(path)function的boost文件系统库
这是太简单的解决scheme吗?
#include <iostream> #include <string> int main() { std::string fn = "filename.conf"; if(fn.substr(fn.find_last_of(".") + 1) == "conf") { std::cout << "Yes..." << std::endl; } else { std::cout << "No..." << std::endl; } }
最好的方法是不写任何代码,而是调用现有的方法。 在Windows中, PathFindExtension方法可能是最简单的。
那么为什么你不写自己的?
那么,以strrchr为例,在下面的string“c:\ program files \ AppleGate.Net \ readme”上使用该方法时会发生什么? 是“.Net \ readme”的扩展名吗? 写一些适用于几个例子的东西是很容易的,但是写一些适用于所有情况的东西会更困难。
假设你有权访问STL:
std::string filename("filename.conf"); std::string::size_type idx; idx = filename.rfind('.'); if(idx != std::string::npos) { std::string extension = filename.substr(idx+1); } else { // No extension found }
编辑:这是一个跨平台的解决scheme,因为你没有提到平台。 如果你是专门在Windows上,你会想利用线程中其他人提到的Windows特定function。
其他人提到提升,但我只是想添加实际的代码来做到这一点:
#include <boost/filesystem.hpp> using std::string; string texture = foo->GetTextureFilename(); string file_extension = boost::filesystem::extension(texture); cout << "attempting load texture named " << texture << " whose extensions seems to be " << file_extension << endl; // Use JPEG or PNG loader function, or report invalid extension
其实STL可以做到这一点,没有太多的代码,我build议你学习一些关于STL,因为它可以让你做一些奇特的事情,反正这是我使用的。
std::string GetFileExtension(const std::string& FileName) { if(FileName.find_last_of(".") != std::string::npos) return FileName.substr(FileName.find_last_of(".")+1); return ""; }
这个解决scheme将总是返回扩展名,即使在“this.abcdesmp3”这样的string中,如果它找不到将返回的扩展名“”。
其实最简单的方法就是
char* ext; ext = strrchr(filename,'.')
有一点要记住:如果'.'
不存在于文件名中,ext将为NULL
。
我自己今天偶然发现了这个问题,尽pipe我已经有了一个工作代码,但我发现它在某些情况下是行不通的。
虽然有些人已经build议使用一些外部库,但我更愿意编写自己的代码来进行学习。
一些答案包括我使用的方法(寻找最后的“。”),但我记得在Linux上隐藏的文件/文件夹以“。”开头。 所以如果文件文件被隐藏并且没有扩展名,那么整个文件名将被作为扩展名。 为了避免我写下这段代码:
bool getFileExtension(const char * dir_separator, const std::string & file, std::string & ext) { std::size_t ext_pos = file.rfind("."); std::size_t dir_pos = file.rfind(dir_separator); if(ext_pos>dir_pos+1) { ext.append(file.begin()+ext_pos,file.end()); return true; } return false; }
我还没有完全testing,但我认为它应该工作。
_splitpath, _wsplitpath, _splitpath_s, _wsplitpath_w
我认为这只是Windows(平台SDK)?
使用std :: string的find / rfind可以解决这个问题,但是如果你在path上工作很多,那么你应该看看boost :: filesystem :: path,因为它会让你的代码比原始的string索引/迭代器更干净。
我build议增强,因为它是一个高质量,经过充分testing,(开源和商业)免费和完全便携式的图书馆。
好的答案,但我看到他们中的大多数有一些问题:首先,我认为一个好的答案应该适用于完整的文件名,其path标题,也应该适用于Linux或Windows或提到它应该跨平台。 对于大部分的答案; 文件名没有扩展名,但文件夹名包括点的path,函数将无法返回正确的扩展名:一些testing用例的例子可能如下:
const char filename1 = {"C:\\init.d\\doc"}; // => No extention const char filename2 = {"..\\doc"}; //relative path name => No extention const char filename3 = {""}; //emputy file name => No extention const char filename4 = {"testing"}; //only single name => No extention const char filename5 = {"tested/k.doc"}; // normal file name => doc const char filename6 = {".."}; // parent folder => No extention const char filename7 = {"/"}; // linux root => No extention const char filename8 = {"/bin/test.d.config/lx.wize.str"}; // ordinary path! => str
“ 布赖恩纽曼 ”build议将失败的文件名1和文件名4。 和其他大部分基于反向查找的答案都会失败,因为filename1。 我build议在你的源代码中包含以下方法:如果没有find,哪个函数返回扩展的第一个字符的索引或给定string的长度。
size_t find_ext_idx(const char* fileName) { size_t len = strlen(fileName); size_t idx = len-1; for(size_t i = 0; *(fileName+i); i++) { if (*(fileName+i) == '.') { idx = i; } else if (*(fileName + i) == '/' || *(fileName + i) == '\\') { idx = len - 1; } } return idx+1; }
你可以在你的c ++应用程序中使用上面的代码,如下所示:
std::string get_file_ext(const char* fileName) { return std::string(fileName).substr(find_ext_idx(fileName)); }
最后一点在某些情况下,一个文件夹被赋予文件名作为参数,并在文件夹名称中包含一个点,该函数将返回文件夹的点尾,以便更好地首先检查给定的名称是文件名而不是文件夹名称。
使用System :: String的NET / CLI版本
System::String^ GetFileExtension(System::String^ FileName) { int Ext=FileName->LastIndexOf('.'); if( Ext != -1 ) return FileName->Substring(Ext+1); return ""; }
对于字符数组types的string,你可以使用这个:
#include <ctype.h> #include <string.h> int main() { char filename[] = "apples.bmp"; char extension[] = ".jpeg"; if(compare_extension(filename, extension) == true) { // ..... } else { // ..... } return 0; } bool compare_extension(char *filename, char *extension) { /* Sanity checks */ if(filename == NULL || extension == NULL) return false; if(strlen(filename) == 0 || strlen(extension) == 0) return false; if(strchr(filename, '.') == NULL || strchr(extension, '.') == NULL) return false; /* Iterate backwards through respective strings and compare each char one at a time */ for(int i = 0; i < strlen(filename); i++) { if(tolower(filename[strlen(filename) - i - 1]) == tolower(extension[strlen(extension) - i - 1])) { if(i == strlen(extension) - 1) return true; } else break; } return false; }
除文件名之外,还可以处理文件path。 适用于C和C ++。 和跨平台。
我会去与boost::filesystem::extension
但如果你不能使用Boost,你只需要validation扩展,一个简单的解决scheme是:
bool ends_with(const std::string &filename, const std::string &ext) { return ext.length() <= filename.length() && std::equal(ext.rbegin(), ext.rend(), filename.rbegin()); } if (ends_with(filename, ".conf")) { /* ... */ }
尝试使用strstr
char* lastSlash; lastSlash = strstr(filename, ".");
或者你可以使用这个:
char *ExtractFileExt(char *FileName) { std::string s = FileName; int Len = s.length(); while(TRUE) { if(FileName[Len] != '.') Len--; else { char *Ext = new char[s.length()-Len+1]; for(int a=0; a<s.length()-Len; a++) Ext[a] = FileName[s.length()-(s.length()-Len)+a]; Ext[s.length()-Len] = '\0'; return Ext; } } }
这个代码是跨平台的
如果你使用Qt库,你可以试试QFileInfo的后缀()
这是一个函数,它将一个path/文件名作为一个string,并以stringforms返回该扩展名。 这是所有标准的C ++,并应该为大多数平台跨平台工作。
与其他几个不同的答案不同,它处理窗口PathFindExtension根据PathFindExtensions文档处理的奇怪情况。
wstring get_file_extension( wstring filename ) { size_t last_dot_offset = filename.rfind(L'.'); // This assumes your directory separators are either \ or / size_t last_dirsep_offset = max( filename.rfind(L'\\'), filename.rfind(L'/') ); // no dot = no extension if( last_dot_offset == wstring::npos ) return L""; // directory separator after last dot = extension of directory, not file. // for example, given C:\temp.old\file_that_has_no_extension we should return "" not "old" if( (last_dirsep_offset != wstring::npos) && (last_dirsep_offset > last_dot_offset) ) return L""; return filename.substr( last_dot_offset + 1 ); }
这是我想出的解决scheme。 然后,我注意到这与@serengeor发布的内容类似。
它适用于std::string
和find_last_of
,但如果修改为使用char
数组和find_last_of
,基本思想也可以工作。 它处理隐藏文件,以及表示当前目录的额外点。 它是平台独立的。
string PathGetExtension( string const & path ) { string ext; // Find the last dot, if any. size_t dotIdx = path.find_last_of( "." ); if ( dotIdx != string::npos ) { // Find the last directory separator, if any. size_t dirSepIdx = path.find_last_of( "/\\" ); // If the dot is at the beginning of the file name, do not treat it as a file extension. // eg, a hidden file: ".alpha". // This test also incidentally avoids a dot that is really a current directory indicator. // eg: "alpha/./bravo" if ( dotIdx > dirSepIdx + 1 ) { ext = path.substr( dotIdx ); } } return ext; }
unit testing:
int TestPathGetExtension( void ) { int errCount = 0; string tests[][2] = { { "/alpha/bravo.txt", ".txt" }, { "/alpha/.bravo", "" }, { ".alpha", "" }, { "./alpha.txt", ".txt" }, { "alpha/./bravo", "" }, { "alpha/./bravo.txt", ".txt" }, { "./alpha", "" }, { "c:\\alpha\\bravo.net\\charlie.txt", ".txt" }, }; int n = sizeof( tests ) / sizeof( tests[0] ); for ( int i = 0; i < n; ++i ) { string ext = PathGetExtension( tests[i][0] ); if ( ext != tests[i][1] ) { ++errCount; } } return errCount; }
我使用这两个函数来获取扩展名和文件名,不带扩展名 :
std::string fileExtension(std::string file){ std::size_t found = file.find_last_of("."); return file.substr(found+1); } std::string fileNameWithoutExtension(std::string file){ std::size_t found = file.find_last_of("."); return file.substr(0,found); }
而这些regex
对于某些额外的要求:
std::string fileExtension(std::string file){ std::regex re(".*[^\\.]+\\.([^\\.]+$)"); std::smatch result; if(std::regex_match(file,result,re))return result[1]; else return ""; } std::string fileNameWithoutExtension(std::string file){ std::regex re("(.*[^\\.]+)\\.[^\\.]+$"); std::smatch result; if(std::regex_match(file,result,re))return result[1]; else return file; }
正则expression式方法满足的额外要求:
- 如果文件名是像
.config
或类似的东西, 扩展名将是一个空string和文件名没有扩展名将是。 - 如果文件名没有任何扩展名,扩展名将是一个空string, 没有扩展名的文件名将是文件名不变。
编辑:
额外的要求也可以通过以下来满足:
std::string fileExtension(const std::string& file){ std::string::size_type pos=file.find_last_of('.'); if(pos!=std::string::npos&&pos!=0)return file.substr(pos+1); else return ""; } std::string fileNameWithoutExtension(const std::string& file){ std::string::size_type pos=file.find_last_of('.'); if(pos!=std::string::npos&&pos!=0)return file.substr(0,pos); else return file; }
注意:
在上述函数中只传递文件名(不是path)。
如果你碰巧使用Poco库,你可以这样做:
#include <Poco/Path.h> ... std::string fileExt = Poco::Path("/home/user/myFile.abc").getExtension(); // == "abc"
如果将扩展名视为最后一个点以及后面的可能字符,但只有当它们不包含目录分隔符时,以下函数才返回扩展开始索引,否则返回-1(如果未find扩展名)。 如果你有,你可以做任何你想要的东西,如剥离扩展名,改变它,检查等。
long get_extension_index(string path, char dir_separator = '/') { // Look from the end for the first '.', // but give up if finding a dir separator char first for(long i = path.length() - 1; i >= 0; --i) { if(path[i] == '.') { return i; } if(path[i] == dir_separator) { return -1; } } return -1; }
我使用PathFindExtension()函数来知道它是否是一个有效的tif文件。
#include <Shlwapi.h> bool A2iAWrapperUtility::isValidImageFile(string imageFile) { char * pStrExtension = ::PathFindExtension(imageFile.c_str()); if (pStrExtension != NULL && strcmp(pStrExtension, ".tif") == 0) { return true; } return false; }