경로에서 파일 이름 가져 오기 간단한 방법은 무엇입니까? string

경로에서 파일 이름을 얻는 가장 간단한 방법은 무엇입니까?

string filename = "C:\\MyDirectory\\MyFile.bat"

이 예에서는 “MyFile”을 가져와야합니다. 확장없이.



답변

_splitpath 는 필요한 작업을 수행해야합니다. 물론 수동으로 할 수 있지만 _splitpath모든 특수한 경우도 처리합니다.

편집하다:

BillHoag가 언급했듯이 가능한 경우 _splitpath_s_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;

답변

가능한 해결책 :

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

답변

기본 파일 이름이 폴더의 마지막 구분자에서 시작하는 문자열의 일부이기 때문에 작업은 매우 간단합니다.

std::string base_filename = path.substr(path.find_last_of("/\\") + 1)

확장 기능도 제거해야하는 경우 마지막 .작업 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…) 와 함께 사용할 수 있도록 템플릿 화되어 있습니다 .

템플릿의 단점은 a 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

답변

가장 간단한 해결책은 boost::filesystem. 어떤 이유로 이것이 옵션이 아닌 경우 …

이 작업을 올바르게 수행하려면 일부 시스템 종속 코드가 필요합니다. Windows에서는 '\\'또는 '/'경로 구분 기호 일 수 있습니다. 유닉스에서는 '/'작동하며 다른 시스템에서는 알 수 있습니다. 명백한 해결책은 다음과 같습니다.

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

코드는 조금 더 복잡합니다. 왜냐하면이 경우 역방향 반복기의베이스가 잘라 내고자하는 곳의 잘못된쪽에 있기 때문입니다. (역방향 반복기의베이스는 반복기가 가리키는 문자 뒤에 있다는 것을 기억하십시오.) 그리고 이것은 조금 모호합니다. 예를 들어 빈 문자열을 반환 할 수 있다는 사실이 마음에 들지 않습니다. (만일 '.'파일 이름의 첫 번째 문자 만 있다면 전체 파일 이름을 반환해야한다고 주장합니다. 특수한 경우를 포착하려면 약간의 추가 코드가 필요합니다.)}


답변

셸 경로 API PathFindFileName, PathRemoveExtension을 사용할 수도 있습니다. 이 특정 문제에 대해 _splitpath보다 나쁠 수 있지만 이러한 API는 모든 종류의 경로 구문 분석 작업에 매우 유용하며 UNC 경로, 슬래시 및 기타 이상한 사항을 고려합니다.

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

이게 다야.

부스트 라이브러리 사용을 권장합니다. Boost는 C ++로 작업 할 때 많은 편의를 제공합니다. 거의 모든 플랫폼을 지원합니다. Ubuntu를 사용하는 경우 한 줄로 부스트 라이브러리를 설치할 수 있습니다 sudo apt-get install libboost-all-dev(참조. Ubuntu에 부스트를 설치하는 방법? ).


답변

C ++ 17에서 가장 간단한 방법은 다음과 같습니다.

사용 #include <filesystem>filename()확장자와 파일 이름을 stem()확장자없이.

    #include <iostream>
    #include <filesystem>
    namespace fs = std::filesystem;

    int main()
    {
        string filename = "C:\\MyDirectory\\MyFile.bat";

    std::cout << fs::path(filename).filename() << '\n'
        << fs::path(filename).stem() << '\n'
        << fs::path("/foo/bar.txt").filename() << '\n'
        << fs::path("/foo/bar.txt").stem() << '\n'
        << fs::path("/foo/.bar").filename() << '\n'
        << fs::path("/foo/bar/").filename() << '\n'
        << fs::path("/foo/.").filename() << '\n'
        << fs::path("/foo/..").filename() << '\n'
        << fs::path(".").filename() << '\n'
        << fs::path("..").filename() << '\n'
        << fs::path("/").filename() << '\n';
    }

산출:

MyFile.bat
MyFile
"bar.txt"
".bar"
"."
"."
".."
"."
".."
"/"

참조 : cppreference