C ++의 문자열에서 파일 확장자를 얻는 방법


80

문자열이 주어지면 "filename.conf"확장 부분을 확인하는 방법은 무엇입니까?

크로스 플랫폼 솔루션이 필요합니다.

답변:


34

하나 이상의 점이있는 파일 이름을 관리해야합니다. 예 : 또는에 c:\.directoryname\file.name.with.too.many.dots.ext의해 올바르게 처리되지 않습니다 .strchrfind.

내가 가장 좋아하는 것은 확장 (경로) 기능이있는 부스트 파일 시스템 라이브러리 입니다.


12
디렉토리 이름은 역방향 찾기로 쉽게 처리됩니다. :).
17 of 26

30
제 개인적인 의견으로는 부스트 솔루션이 C ++ 문제에 대한 답변으로 나열되어서는 안됩니다. 너무 간단한 것을 위해 외부 라이브러리를 요구하는 것은 약간 어리석은 것처럼 보입니다.
습지

4
@marsh :하지만, 아주 간단한 문제는 특별한 경우가 있습니다. 특히 파일 시스템을 다룰 때-거의 모든 주요 (그렇지 않은) 운영 체제가 자체적으로 해석하는 개념입니다. 예를 들어, Linux 숨김 파일 (`/home/oren/.conf ') 또는 @Torlack에서 언급 한 경우 를 고려하십시오 . @ 17 / 26, 사용자 이름 만 언급하려고하면 사람들이 자유 형식 이름 지정을 사용하는 방법을 지나치게 단순화하여 발생할 수있는 문제를 강조해야합니다.)
Oren S

@OrenS 그럼에도 불구하고 부스트 솔루션은 부스트로 수행하는 방법을 묻지 않는 질문에 대한 답변으로 받아 들여서는 안됩니다. 오해의 소지가 있습니다.
Silidrone

@MuhamedCicak ... 음, othervise를위한 휴대용 솔루션에는 파일 이름 인코딩을 고려하거나 다른 라이브러리를 사용하는 긴 코드가 포함됩니다 (부스트는 처음부터 구현하지 않고 대신 다른 패키지 또는 API를 사용합니다. 가능한). 작업으로 부분적 경로에서 표준 경로를 얻는 것도 6 개의 엣지 케이스에서 큰 문제입니다.
Swift-Friday Pie

156

이것이 너무 간단한 해결책입니까?

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

12
@ 파일 이름에 확장자가없고 이전 폴더에. 이름으로?
Mircea Ispas 2013

4
나는 질문에 대답하고있다. 가상이 아닌 "filename.conf"를 지정합니다.
brian newman 2013 년

5
그 논리에 따르면, return "Yes...";확인하지 않고 말할 수 있습니다 . 솔루션이 다른 입력에 대해 작동해야 함을 의미합니다. 또 다른 카운터 예로서, 확장자가없는 단순히 "conf"라는 파일도 위의 경우 "Yes ..."를 반환합니다.
Rollie

4
다른 사람에게 경고 : 다양한 실제 최종 사용자 시나리오를 처리 할 필요가없는 좁은 특정 프로젝트를 제외하고는 프로덕션 코드에서 사용하기에는 너무 간단한 솔루션입니다. 파일 이름 구문 분석 및 처리는 중요하지 않습니다. 저는 개인적으로 거의 항상를 사용하는데 boost::filesystem, 사용하기는 쉽지만 필요한 지원을 제공합니다. boost.org/doc/libs/1_55_0/libs/filesystem/doc/index.htm
Dan Nissenbaum 2014

1
std :: filesystem :: path :: extension 은 이제 표준의 일부입니다 . 아래 Roi Danton 답변을 확인하십시오 .
yves

42

가장 좋은 방법은이를 수행하는 코드를 작성하지 않고 기존 메서드를 호출하는 것입니다. Windows에서는 PathFindExtension 메서드가 가장 간단 할 것입니다.

그렇다면 왜 직접 작성하지 않겠습니까?

자, strrchr 예제를 보시죠. "c : \ program files \ AppleGate.Net \ readme"문자열에서 그 방법을 사용하면 어떻게됩니까? ".Net \ readme"가 확장자입니까? 몇 가지 사례에서 작동하는 것을 작성하는 것은 쉽지만 모든 사례에서 작동하는 것을 작성하는 것은 훨씬 더 어려울 수 있습니다.


3
+1 새 코드를 작성하지 않는 것이 가장 좋은 대답입니다! 이것의 C # 버전은 내가 방금 후에 있었던 것이었지만 귀하의 대답은 저를 거기에 가져 왔습니다. msdn.microsoft.com/en-us/library/…
Tom Resing 2011 년

이 기능 (Windows 7에서)은 "file.i i"를 제대로 처리하지 못합니다. 예, 이것은 유효합니다. 공간을 확인하십시오.
pcunite 2013-08-27

그는 전체 경로가 아닌 파일에서 확장자를 검색하는 것에 대해 질문했습니다. 또한 Windows API 기능은 좋은 대답이 아닙니다. 이것은 절대적으로 대답이 아니라 의견입니다.
디닥 페레즈 Parera

4
-1-OP에서 포터블 솔루션 요청시 플랫폼 별 솔루션 제공
jb

+1 나에게서. 이 질문은 Google 'mfc get file extension'때 나타나는 첫 번째 질문이며 귀하의 질문이 작동하는 가장 간단한 대답입니다.
Eternal21

32

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 특정 기능을 활용하고 싶을 것입니다.


6
+1, 이것은 경로가 아닌 문자열에 파일 이있는 경우 가장 간단한 솔루션입니다 !
Thomas Bonini

25

다른 누군가가 부스트를 언급했지만이 작업을 수행하기 위해 실제 코드를 추가하고 싶었습니다.

#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

20

실제로 STL은 많은 코드없이이 작업을 수행 할 수 있습니다. 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.abcdesmp3"와 같은 문자열에서도 항상 확장자를 반환합니다. 확장자를 찾을 수 없으면 ""를 반환합니다.


15

C ++ 17과 그 std::filesystem::path::extension(라이브러리가 boost :: filesystem의 후속 제품 임)를 사용하면 eg를 사용하는 것보다 더 표현력있는 문장을 만들 수 있습니다 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"
    }
}

참조 표준 : 파일 시스템 :: 경로 : 줄기 , 표준 : : 파일 시스템 : 경로 : 파일 이름을 .


7

사실 가장 쉬운 방법은

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

기억해야 할 한 가지 : '.'파일 이름에 존재하지 않으면 ext는 NULL.


4
이 점으로 시작 UNIX 숨겨진 파일에 대한 완벽한 솔루션되지 않을 것
마크 칸

const char * ext 여야합니까?
Vlad

4

나는 이미 작동하는 코드가 있지만 어떤 경우에는 작동하지 않을 것이라는 것을 알았음에도 불구하고 오늘이 질문을 우연히 발견했습니다.

일부 사람들은 이미 외부 라이브러리 사용을 제안했지만 학습 목적으로 자체 코드를 작성하는 것을 선호합니다.

일부 답변에는 처음에 사용했던 방법 (마지막 "."찾기)이 포함되어 있지만 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;
}

나는 이것을 완전히 테스트하지는 않았지만 작동해야한다고 생각합니다.


3

std :: string의 find / rfind를 사용하면이 문제가 해결되지만 경로를 많이 사용한다면 boost :: filesystem :: path를 살펴보아야합니다. 원시 문자열 인덱스 / 반복자를 조작하는 것보다 코드를 훨씬 더 깔끔하게 만들 수 있기 때문입니다.

나는 그것이 고품질이고 잘 테스트되고 (오픈 소스 및 상업적으로) 무료이며 완전히 이식 가능한 라이브러리이기 때문에 boost를 제안합니다.


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 ++ 모두에서 작동합니다. 그리고 크로스 플랫폼.


조건 수를 줄일 수 있습니다. 조건 strlen(extension)에서 사용하십시오 for. 그런 다음 문자가 일치하지 않으면 false를 반환합니다. 외부 for루프는 참을 반환합니다.
LRDPRDX

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

" brian newman "제안은 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));
}

경우에 따라 폴더가 인수로 파일 이름에 제공되고 폴더 이름에 점이 포함 된 경우 함수는 폴더의 점 후행을 반환하므로 지정된 이름이 폴더 이름이 아닌 파일 이름인지 먼저 확인하는 것이 좋습니다.


3

System :: String을 사용하는 NET / CLI 버전

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

이것은 Visual C ++가 아니라 .NET / CLI 입니다.
빅터

1
@Victor 나는 대답을 편집했습니다. 설명해 주셔서 감사합니다.
Leopoldo Sanczyk

3

나는 boost::filesystem::extension( std::filesystem::path::extensionC ++ 17로) 함께 갈 것이지만 Boost를 사용할 수없고 확장을 확인해야하는 경우 간단한 해결책은 다음과 같습니다.

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"))
{ /* ... */ }

3
_splitpath, _wsplitpath, _splitpath_s, _wsplitpath_w

Windows (Platform SDK) 전용입니다.


2

이것은 내가 생각해 낸 해결책입니다. 그런 다음 @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;
}

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;

}

regex 메소드로 충족되는 추가 요구 사항 :

  1. 경우 파일 이름이 비슷 .config하거나 같은, 확장은 빈 문자열이 될 것이다 확장자가없는 파일 이름이 될 것입니다 .config.
  2. 파일 이름에 확장자가없는 경우 확장자는 빈 문자열이되고 확장자없는 파일 이름은 변경되지 않은 파일 이름이 됩니다.

편집하다:

추가 요구 사항은 다음과 같은 방법으로도 충족 될 수 있습니다.

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

노트 :

위의 함수에서 경로가 아닌 파일 이름 만 전달하십시오.



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

이 코드는 크로스 플랫폼입니다.


1

Qt 라이브러리를 사용하는 경우 QFileInfosuffix () 시도해 볼 수 있습니다.


2
Qt는이 질문과 무슨 관련이 있습니까? 간단한 문자열 조작을 위해 대규모 타사 종속성을 도입하는 이유는 무엇입니까? 그 길을 가면 왜 부스트를 사용하지 않습니까?
derpface

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

안녕하세요, 솔루션에 문제가 있습니다. max( filename.rfind(L'\\'), filename.rfind(L'/') )두 개의 부호없는 값을 비교합니다. 그중 하나는 npos가능한 가장 큰 부호없는 정수일 수 있습니다. 따라서 폴더가 있어도 폴더가없는 것처럼 보일 수 있습니다!
Andrii Kovalevskyi 2015

0

Poco 라이브러리 를 사용하는 경우 다음 을 수행 할 수 있습니다.

#include <Poco/Path.h>

...

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

0

확장자를 마지막 점과 그 뒤의 가능한 문자로 간주하지만 디렉토리 구분 문자를 포함하지 않는 경우에만 다음 함수는 확장자 시작 색인을 반환하거나 확장자가 없으면 -1을 반환합니다. 확장 프로그램을 제거하고 변경하고 확인하는 등 원하는 작업을 수행 할 수 있습니다.

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

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

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;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.