경로에서 파일 이름 가져 오기
경로에서 파일 이름을 얻는 가장 간단한 방법은 무엇입니까?
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 );
}
코드는 조금 더 복잡합니다. 왜냐하면이 경우 역방향 반복기의베이스가 잘라 내고자하는 곳의 잘못된쪽에 있기 때문입니다. (역방향 반복기의베이스는 반복기가 가리키는 문자 뒤에 있다는 것을 기억하십시오.) 그리고 이것은 조금 모호합니다. 예를 들어 빈 문자열을 반환 할 수 있다는 사실이 마음에 들지 않습니다. (만일 '.'
파일 이름의 첫 번째 문자 만 있다면 전체 파일 이름을 반환해야한다고 주장합니다. 특수한 경우를 포착하려면 약간의 추가 코드가 필요합니다.)}
부스트를 사용할 수 있다면
#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에 부스트를 설치하는 방법? ).
셸 경로 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 <string>
std::string
basename(const std::string &filename)
{
if (filename.empty()) {
return {};
}
auto len = filename.length();
auto index = filename.find_last_of("/\\");
if (index == std::string::npos) {
return filename;
}
if (index + 1 >= len) {
len--;
index = filename.substr(0, len).find_last_of("/\\");
if (len == 0) {
return filename;
}
if (index == 0) {
return filename.substr(1, len - 1);
}
if (index == std::string::npos) {
return filename.substr(0, len);
}
return filename.substr(index + 1, len - index - 1);
}
return filename.substr(index + 1, len - index);
}
테스트 :
#define CATCH_CONFIG_MAIN
#include <catch/catch.hpp>
TEST_CASE("basename")
{
CHECK(basename("") == "");
CHECK(basename("no_path") == "no_path");
CHECK(basename("with.ext") == "with.ext");
CHECK(basename("/no_filename/") == "no_filename");
CHECK(basename("no_filename/") == "no_filename");
CHECK(basename("/no/filename/") == "filename");
CHECK(basename("/absolute/file.ext") == "file.ext");
CHECK(basename("../relative/file.ext") == "file.ext");
CHECK(basename("/") == "/");
CHECK(basename("c:\\windows\\path.ext") == "path.ext");
CHECK(basename("c:\\windows\\no_filename\\") == "no_filename");
}
cpp17에서 가장 간단한 방법은 다음과 같습니다.
확장자가있는 파일 이름에는 #include experiment / filesystem 및 filename ()을 사용하고 확장자가없는 stem ()을 사용하십시오.
#include <iostream>
#include <experimental/filesystem>
namespace fs = std::experimental::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
C ++ 문서에서 -string :: find_last_of
#include <iostream> // std::cout
#include <string> // std::string
void SplitFilename (const std::string& str) {
std::cout << "Splitting: " << str << '\n';
unsigned found = str.find_last_of("/\\");
std::cout << " path: " << str.substr(0,found) << '\n';
std::cout << " file: " << str.substr(found+1) << '\n';
}
int main () {
std::string str1 ("/usr/bin/man");
std::string str2 ("c:\\windows\\winhelp.exe");
SplitFilename (str1);
SplitFilename (str2);
return 0;
}
출력 :
Splitting: /usr/bin/man
path: /usr/bin
file: man
Splitting: c:\windows\winhelp.exe
path: c:\windows
file: winhelp.exe
균일 한 초기화 및 익명 인라인 람다를 사용하는 C ++ 11 변형 (James Kanze 버전에서 영감을 얻음).
std::string basename(const std::string& pathname)
{
return {std::find_if(pathname.rbegin(), pathname.rend(),
[](char c) { return c == '/'; }).base(),
pathname.end()};
}
하지만 파일 확장자를 제거하지는 않습니다.
boost
filesystem
라이브러리는 또한으로 사용할 experimental/filesystem
라이브러리와 C ++ (17)에 대한 ++ ISO C에 합병되었다. 다음과 같이 사용할 수 있습니다.
#include <iostream>
#include <experimental/filesystem>
namespace fs = std::experimental::filesystem;
int main () {
std::cout << fs::path("/foo/bar.txt").filename() << '\n'
}
산출:
"bar.txt"
그것은 또한 std::string
개체에 대해 작동 합니다.
이것은 실제로 마침내 나를 위해 일한 유일한 것입니다.
#include "Shlwapi.h"
CString some_string = "c:\\path\\hello.txt";
LPCSTR file_path = some_string.GetString();
LPCSTR filepart_c = PathFindFileName(file_path);
LPSTR filepart = LPSTR(filepart_c);
PathRemoveExtension(filepart);
Skrymsli가 제안한 것과 거의 같지만 wchar_t *, VS Enterprise 2015에서는 작동하지 않습니다.
_splitpath도 작동했지만 얼마나 많은 char [?] 문자가 필요한지 추측 할 필요가 없습니다. 어떤 사람들은 아마도이 컨트롤이 필요할 것 같습니다.
CString c_model_name = "c:\\path\\hello.txt";
char drive[200];
char dir[200];
char name[200];
char ext[200];
_splitpath(c_model_name, drive, dir, name, ext);
_splitpath에는 포함이 필요하지 않다고 생각합니다. 이러한 솔루션에는 외부 라이브러리 (예 : boost)가 필요하지 않았습니다.
나는 그것을 할 것입니다 ...
첫 번째 백 슬래시 / 슬래시를 찾을 때까지 문자열 끝에서 뒤로 검색합니다.
그런 다음 첫 번째 점 (.)을 찾을 때까지 문자열 끝에서 뒤로 검색합니다.
그러면 파일 이름의 시작과 끝이 있습니다.
단순 ...
m_szFilePath.MakeLower();
CFileFind finder;
DWORD buffSize = MAX_PATH;
char longPath[MAX_PATH];
DWORD result = GetLongPathName(m_szFilePath, longPath, MAX_PATH );
if( result == 0)
{
m_bExists = FALSE;
return;
}
m_szFilePath = CString(longPath);
m_szFilePath.Replace("/","\\");
m_szFilePath.Trim();
//check if it does not ends in \ => remove it
int length = m_szFilePath.GetLength();
if( length > 0 && m_szFilePath[length - 1] == '\\' )
{
m_szFilePath.Truncate( length - 1 );
}
BOOL bWorking = finder.FindFile(this->m_szFilePath);
if(bWorking){
bWorking = finder.FindNextFile();
finder.GetCreationTime(this->m_CreationTime);
m_szFilePath = finder.GetFilePath();
m_szFileName = finder.GetFileName();
this->m_szFileExtension = this->GetExtension( m_szFileName );
m_szFileTitle = finder.GetFileTitle();
m_szFileURL = finder.GetFileURL();
finder.GetLastAccessTime(this->m_LastAccesTime);
finder.GetLastWriteTime(this->m_LastWriteTime);
m_ulFileSize = static_cast<unsigned long>(finder.GetLength());
m_szRootDirectory = finder.GetRoot();
m_bIsArchive = finder.IsArchived();
m_bIsCompressed = finder.IsCompressed();
m_bIsDirectory = finder.IsDirectory();
m_bIsHidden = finder.IsHidden();
m_bIsNormal = finder.IsNormal();
m_bIsReadOnly = finder.IsReadOnly();
m_bIsSystem = finder.IsSystem();
m_bIsTemporary = finder.IsTemporary();
m_bExists = TRUE;
finder.Close();
}else{
m_bExists = FALSE;
}
m_szFileName 변수에는 fileName이 포함됩니다.
그나마 사용 _splitpath()
하고 _wsplitpath()
. 그들은 안전하지 않으며 쓸모가 없습니다!
대신, 즉, 자신의 안전 버전을 사용 _splitpath_s()
하고_wsplitpath_s()
이것도 작동합니다.
// strPath = "C:\\Dir\\File.bat" for example
std::string getFileName(const std::string& strPath)
{
size_t iLastSeparator = 0;
return strPath.substr((iLastSeparator = strPath.find_last_of("\\")) != std::string::npos ? iLastSeparator + 1 : 0, strPath.size() - strPath.find_last_of("."));
}
당신이 그것을 사용할 수 있다면, Qt는 파일, 파일 이름 및 디렉토리를 조작하기 위해 QString (분할, 트림 등), QFile, QPath, QFileInfo 등을 제공합니다. 그리고 물론 그것은 또한 교차 플랫폼입니다.
std::string getfilename(std::string path)
{
path = path.substr(path.find_last_of("/\\") + 1);
size_t dot_i = path.find_last_of('.');
return path.substr(0, dot_i);
}
오랫동안 파일 경로를 적절하게 분해 할 수있는 기능을 찾고있었습니다. 저에게이 코드는 Linux와 Windows 모두에서 완벽하게 작동합니다.
void decomposePath(const char *filePath, char *fileDir, char *fileName, char *fileExt)
{
#if defined _WIN32
const char *lastSeparator = strrchr(filePath, '\\');
#else
const char *lastSeparator = strrchr(filePath, '/');
#endif
const char *lastDot = strrchr(filePath, '.');
const char *endOfPath = filePath + strlen(filePath);
const char *startOfName = lastSeparator ? lastSeparator + 1 : filePath;
const char *startOfExt = lastDot > startOfName ? lastDot : endOfPath;
if(fileDir)
_snprintf(fileDir, MAX_PATH, "%.*s", startOfName - filePath, filePath);
if(fileName)
_snprintf(fileName, MAX_PATH, "%.*s", startOfExt - startOfName, startOfName);
if(fileExt)
_snprintf(fileExt, MAX_PATH, "%s", startOfExt);
}
결과 예는 다음과 같습니다.
[]
fileDir: ''
fileName: ''
fileExt: ''
[.htaccess]
fileDir: ''
fileName: '.htaccess'
fileExt: ''
[a.exe]
fileDir: ''
fileName: 'a'
fileExt: '.exe'
[a\b.c]
fileDir: 'a\'
fileName: 'b'
fileExt: '.c'
[git-archive]
fileDir: ''
fileName: 'git-archive'
fileExt: ''
[git-archive.exe]
fileDir: ''
fileName: 'git-archive'
fileExt: '.exe'
[D:\Git\mingw64\libexec\git-core\.htaccess]
fileDir: 'D:\Git\mingw64\libexec\git-core\'
fileName: '.htaccess'
fileExt: ''
[D:\Git\mingw64\libexec\git-core\a.exe]
fileDir: 'D:\Git\mingw64\libexec\git-core\'
fileName: 'a'
fileExt: '.exe'
[D:\Git\mingw64\libexec\git-core\git-archive.exe]
fileDir: 'D:\Git\mingw64\libexec\git-core\'
fileName: 'git-archive'
fileExt: '.exe'
[D:\Git\mingw64\libexec\git.core\git-archive.exe]
fileDir: 'D:\Git\mingw64\libexec\git.core\'
fileName: 'git-archive'
fileExt: '.exe'
[D:\Git\mingw64\libexec\git-core\git-archiveexe]
fileDir: 'D:\Git\mingw64\libexec\git-core\'
fileName: 'git-archiveexe'
fileExt: ''
[D:\Git\mingw64\libexec\git.core\git-archiveexe]
fileDir: 'D:\Git\mingw64\libexec\git.core\'
fileName: 'git-archiveexe'
fileExt: ''
나는 이것이 당신에게도 도움이되기를 바랍니다 :)
shlwapi.lib/dll
HKCU
레지스트리 하이브를 내부적으로 사용합니다 .
shlwapi.lib
라이브러리를 만들거나 제품에 UI가없는 경우 연결하지 않는 것이 가장 좋습니다 . lib를 작성하는 경우 UI가없는 프로젝트를 포함하여 모든 프로젝트에서 코드를 사용할 수 있습니다.
If you're writing code that runs when a user is not logged in (e.g. service [or other] set to start at boot or startup) then there's no HKCU
. Lastly, shlwapi are settlement functions; and as a result high on the list to deprecate in later versions of Windows.
You can use the std::filesystem to do it quite nicely:
#include <filesystem>
namespace fs = std::experimental::filesystem;
fs::path myFilePath("C:\\MyDirectory\\MyFile.bat");
fs::path filename = myFilePath.stem();
참고URL : https://stackoverflow.com/questions/8520560/get-a-file-name-from-a-path
'programing' 카테고리의 다른 글
Web.Config의 전자 메일 표시 이름에서 Smtp 저장 (0) | 2020.10.26 |
---|---|
RecyclerView / LinearLayoutManager가 상단 또는 하단으로 스크롤되는지 확인하는 방법은 무엇입니까? (0) | 2020.10.25 |
jQuery에서 getJSON에 대해 캐시를 false로 설정하는 방법은 무엇입니까? (0) | 2020.10.25 |
문자열을 열거 형으로 캐스팅 (0) | 2020.10.25 |
Angular.js 및 Bootstrap 양식 유효성 검사 스타일 조정 (0) | 2020.10.25 |