How to get file extension from string in C++

前端 未结 25 2422
迷失自我
迷失自我 2020-11-30 22:35

Given a string \"filename.conf\", how to I verify the extension part?

I need a cross platform solution.

相关标签:
25条回答
  • 2020-11-30 23:24

    You have to make sure you take care of file names with more then one dot. example: c:\.directoryname\file.name.with.too.many.dots.ext would not be handled correctly by strchr or find.

    My favorite would be the boost filesystem library that have an extension(path) function

    0 讨论(0)
  • 2020-11-30 23:24

    With C++17 and its std::filesystem::path::extension (the library is the successor to boost::filesystem) you would make your statement more expressive than using e.g. 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"
        }
    }
    

    See also std::filesystem::path::stem, std::filesystem::path::filename.

    0 讨论(0)
  • 2020-11-30 23:25

    I've stumbled onto this question today myself, even though I already had a working code I figured out that it wouldn't work in some cases.

    While some people already suggested using some external libraries, I prefer to write my own code for learning purposes.

    Some answers included the method I was using in the first place (looking for the last "."), but I remembered that on linux hidden files/folders start with ".". So if file file is hidden and has no extension, the whole file name would be taken for extension. To avoid that I wrote this piece of code:

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

    I haven't tested this fully, but I think that it should work.

    0 讨论(0)
  • 2020-11-30 23:26

    Good answers but I see most of them has some problems: First of all I think a good answer should work for complete file names which have their path headings, also it should work for linux or windows or as mentioned it should be cross platform. For most of answers; file names with no extension but a path with a folder name including dot, the function will fail to return the correct extension: examples of some test cases could be as follow:

        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
    

    "brian newman" suggestion will fail for filename1 and filename4. and most of other answers which are based on reverse find will fail for filename1. I suggest including the following method in your source: which is function returning index of first character of extension or the length of given string if not found.

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

    you could use the above code in your c++ application like below:

    std::string get_file_ext(const char* fileName)
    {
        return std::string(fileName).substr(find_ext_idx(fileName));
    }
    

    The last point in some cases the a folder is given to file name as argument and includes a dot in the folder name the function will return folder's dot trailing so better first to user check that the given name is a filename and not folder name.

    0 讨论(0)
  • 2020-11-30 23:27

    Here's a function that takes a path/filename as a string and returns the extension as a string. It is all standard c++, and should work cross-platform for most platforms.

    Unlike several other answers here, it handles the odd cases that windows' PathFindExtension handles, based on PathFindExtensions's documentation.

    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 );
    }
    
    0 讨论(0)
  • 2020-11-30 23:28
    _splitpath, _wsplitpath, _splitpath_s, _wsplitpath_w
    

    This is Windows (Platform SDK) only

    0 讨论(0)
提交回复
热议问题