如何从C ++中的字符串获取文件扩展名

时间:2008-09-09 13:57:34

标签: c++ string filenames

给定字符串"filename.conf",如何验证扩展部分?

我需要跨平台解决方案。

23 个答案:

答案 0 :(得分:137)

解决方案太简单了吗?

#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;
  }
}

答案 1 :(得分:43)

最好的方法是不要编写任何代码,而是调用现有方法。在Windows中,PathFindExtension方法可能是最简单的方法。

那你为什么不写自己的?

那么,以strrchr为例,当您对以下字符串“c:\ program files \ AppleGate.Net \ readme”使用该方法时会发生什么? “。Net \ readme”是扩展名吗?编写适用于少数示例案例的内容很容易,但编写适用于所有案例的内容会更加困难。

答案 2 :(得分:34)

您必须确保使用多个点来处理文件名。 示例:c:\.directoryname\file.name.with.too.many.dots.extstrchr

无法正确处理find.

我最喜欢的是具有扩展(路径)功能的boost filesystem library

答案 3 :(得分:30)

假设您有权访问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
}

编辑:这是一个跨平台解决方案,因为您没有提及该平台。如果您专门在Windows上,则需要利用线程中其他人提到的Windows特定功能。

答案 4 :(得分:23)

其他人提到了提升,但我只想添加实际代码来执行此操作:

#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

答案 5 :(得分:17)

实际上STL可以在没有太多代码的情况下做到这一点,我建议你先了解一下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 "";
}

此解决方案将始终返回扩展名,即使在“this.a.b.c.d.e.s.mp3”等字符串上也是如此,如果找不到它将返回的扩展名“”。

答案 6 :(得分:8)

实际上,最简单的方法是

char* ext;
ext = strrchr(filename,'.') 

要记住的一件事:如果文件名中不存在'.',则ext将为NULL

答案 7 :(得分:5)

我今天偶然发现了这个问题,尽管我已经有了一个可行的代码,但我发现它在某些情况下不起作用。

虽然有些人已经建议使用一些外部库,但我更喜欢编写自己的代码用于学习目的。

一些答案​​包括我首先使用的方法(寻找最后一个“。”),但我记得在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;
}

我没有对此进行过全面测试,但我认为它应该可行。

答案 8 :(得分:4)

_splitpath, _wsplitpath, _splitpath_s, _wsplitpath_w

我认为这只是Windows(Platform SDK)?

答案 9 :(得分:3)

使用System :: String

的NET / CLI版本
   System::String^ GetFileExtension(System::String^ FileName)
   {
       int Ext=FileName->LastIndexOf('.');
       if( Ext != -1 )
           return FileName->Substring(Ext+1);
       return "";
   }

答案 10 :(得分:3)

对于char数组类型字符串,您可以使用:

#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;
}

除文件名外,还可以处理文件路径。适用于C和C ++。跨平台。

答案 11 :(得分:3)

使用std :: string的find / rfind解决了这个问题,但是如果你使用路径工作很多,那么你应该看看boost :: filesystem :: path,因为它会使你的代码比摆弄原始字符串索引更清晰/迭代器。

我建议提升,因为它是一个高质量,经过良好测试,(开源和商业)免费且完全便携的库。

答案 12 :(得分:3)

答案很好,但我发现其中大多数都有一些问题: 首先,我认为一个好的答案应该适用于具有路径标题的完整文件名,也适用于Linux或Windows,或者如上所述它应该是跨平台的。对于大多数答案;文件名没有扩展名但文件夹名称包含点的路径,该函数将无法返回正确的扩展名:某些测试用例的示例如下:

    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

&#34; brian newman &#34;对于filename1和filename4,建议将失败。 并且大多数基于反向查找的其他答案都将因filename1而失败。 我建议在您的源代码中包含以下方法: 这是函数返回扩展名第一个字符的索引或者找不到给定字符串的长度。

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));
}

在某些情况下最后一点是一个文件夹被赋予文件名作为参数,并且在文件夹名称中包含一个点,该函数将返回文件夹的点尾部,因此最好先用户检查给定的名称是否为文件名而不是文件夹名称。

答案 13 :(得分:3)

使用C ++ 17及其std::filesystem::path::extension(该库是boost :: filesystem的后继者),你可以使你的语句比使用例如std::string

#include <iostream>
#include <filesystem> // C++17
namespace fs = std::filesystem;

int main()
{
    fs::path filePath = "my/path/to/myFile.conf";
    if (filePath.extension() == ".conf") // Heed the dot.
    {
        std::cout << filePath.stem() << " is a valid type."; // Output: "myFile is a valid type."
    }
    else
    {
        std::cout << filePath.filename() << " is an invalid type."; // Output: e.g. "myFile.cfg is an invalid type"
    }
}

另请参阅std::filesystem::path::stemstd::filesystem::path::filename

答案 14 :(得分:2)

我使用这两个函数来获取扩展名文件名而不使用扩展名

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;

}

正则表达式方法满足的额外要求:

  1. 如果 filename 类似.config或类似内容,扩展名将为空字符串,文件名不带扩展名将是.config
  2. 如果文件名没有任何扩展名,则扩展名为空字符串, filename不带扩展名 filename 保持不变。
  3. 修改

    以下内容也可以满足额外要求:

    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;
    }
    

    注意:

    仅传递上述函数中的文件名(不是路径)。

答案 15 :(得分:1)

尝试使用strstr

char* lastSlash;
lastSlash = strstr(filename, ".");

答案 16 :(得分:1)

或者你可以使用它:

    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;
            }
        }
    }

此代码是跨平台的

答案 17 :(得分:1)

如果您使用Qt库,可以试试QFileInfosuffix()

答案 18 :(得分:1)

这是一个将路径/文件名作为字符串并将扩展名作为字符串返回的函数。它是所有标准的c ++,并且应该适用于大多数平台的跨平台。

与此处的其他几个答案不同,它根据PathFindExtensions的文档处理Windows'PathFindExtension处理的奇怪情况。

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 );
}

答案 19 :(得分:1)

这是我提出的解决方案。然后,我注意到它与@serengeor发布的相似。

它适用于std::stringfind_last_of,但如果修改为使用char数组和strrchr,基本提示也会有效。 它处理隐藏文件,以及代表当前目录的额外点。它与平台无关。

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.
    // e.g., a hidden file:  ".alpha".
    // This test also incidentally avoids a dot that is really a current directory indicator.
    // e.g.:  "alpha/./bravo"
    if ( dotIdx > dirSepIdx + 1 )
    {
      ext = path.substr( dotIdx );
    }
  }

  return ext;
}

单元测试:

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;
}

答案 20 :(得分:0)

如果您碰巧使用Poco库,则可以执行以下操作:

#include <Poco/Path.h>

...

std::string fileExt = Poco::Path("/home/user/myFile.abc").getExtension(); // == "abc"

答案 21 :(得分:0)

我使用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;
}

答案 22 :(得分:0)

您可以使用 strrchr()查找最后出现的。(点)并获取基于。(点)的扩展文件。 例如,检查以下代码。

#include<stdio.h>

void GetFileExtension(const char* file_name) {

    int ext = '.';
    const char* extension = NULL;
    extension = strrchr(file_name, ext);

    if(extension == NULL){
        printf("Invalid extension encountered\n");
        return;
    }

    printf("File extension is %s\n", extension);
}

int main()
{
    const char* file_name = "c:\\.directoryname\\file.name.with.too.many.dots.ext";
    GetFileExtension(file_name);
    return 0;
}