एक पथ से फ़ाइल नाम प्राप्त करने का सबसे सरल तरीका क्या है?
string filename = "C:\\MyDirectory\\MyFile.bat"
इस उदाहरण में, मुझे "MyFile" मिलना चाहिए। बिना विस्तार के।
एक पथ से फ़ाइल नाम प्राप्त करने का सबसे सरल तरीका क्या है?
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;
_splitpath
मेरी मशीन में कोई भी शामिल नहीं है।
<stdlib.h>
। पोर्टेबिलिटी के लिए, शायद आप "पूरी तरह से अच्छा पोर्टेबल समाधान" के कुछ उदाहरणों को सूचीबद्ध कर सकते हैं?
<stdlib.h>
। और स्पष्ट स्पष्ट पोर्टेबल समाधान है boost::filesystem
।
_splitpath
में stdlib.h
वी.एस. की अपनी प्रतिलिपि की? तब आप VS की मरम्मत स्थापित करना चाहते हैं।
एक संभावित समाधान:
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
...)
const char *
कार्य के लिए पास होने पर टेम्प्लेशन का नकारात्मक पहलू टेम्पलेट पैरामीटर को निर्दिष्ट करने की आवश्यकता है ।
तो आप या तो कर सकते हैं:
std::string
कोड को गति देने के बजाय केवल उपयोग करेंstd::string base_name(std::string const & path)
{
return path.substr(path.find_last_of("/\\") + 1);
}
std::string
(मध्यवर्ती के रूप में जो संभवतः अंतर्निर्मित / अनुकूलित दूर होगा)inline std::string string_base_name(std::string const & path)
{
return base_name(path);
}
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
base_name
पहले आवेदन करें ।)
सबसे सरल उपाय कुछ का उपयोग करना है 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 == '/';
}
};
यूनिक्स के लिए, या:
struct MatchPathSeparator
{
bool operator()( char ch ) const
{
return ch == '\\' || ch == '/';
}
};
विंडोज के लिए (या कुछ अन्य अज्ञात सिस्टम के लिए अभी भी कुछ अलग है)।
संपादित करें: मैंने इस तथ्य को याद किया कि वह भी निरोध को दबाना चाहता था। उसके लिए, उसी के अधिक:
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 );
}
कोड थोड़ा अधिक जटिल है, क्योंकि इस मामले में, रिवर्स पुनरावृत्ति का आधार गलत पक्ष पर है जहां हम कटौती करना चाहते हैं। (याद रखें कि रिवर्स इटरेटर का आधार चरित्र के पीछे एक है जो इट्रेटर इंगित करता है।) और यहां तक कि यह थोड़ा संदिग्ध है: मुझे इस तथ्य को पसंद नहीं है कि यह खाली स्ट्रिंग लौटा सकता है, उदाहरण के लिए। (यदि केवल '.'
फ़ाइल नाम का पहला वर्ण है, तो मेरा तर्क है कि आपको पूरा फ़ाइल नाम वापस करना चाहिए। विशेष मामले को पकड़ने के लिए थोड़ा अतिरिक्त कोड की आवश्यकता होगी।)}
string::find_last_of
रिवर्स पुनरावृत्तियों में हेरफेर करने के बजाय उपयोग करने के बारे में ?
string
, इसलिए आपको उन्हें वैसे भी सीखना होगा। और उन्हें सीखा, फूला हुआ इंटरफ़ेस के सभी सीखने के लिए परेशान करने का कोई कारण नहीं है std::string
।
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
आप शेल पाथ APIs 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();
बस इतना ही।
मैं आपको बढ़ावा पुस्तकालय का उपयोग करने की सलाह देता हूं। जब आप C ++ के साथ काम करते हैं तो बूस्ट आपको बहुत सारी सुविधाएं देता है। यह लगभग सभी प्लेटफार्मों का समर्थन करता है। यदि आप उबंटू का उपयोग करते हैं, तो आप केवल एक लाइन sudo apt-get install libboost-all-dev
(रेफरी। उबंटू पर बढ़ावा कैसे स्थापित करें? ) द्वारा बूस्ट लाइब्रेरी स्थापित कर सकते हैं ।
समारोह:
#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");
}
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
find_last_of
रिटर्न string::npos
अगर कुछ भी नहीं मिला था।
string::npos
जिस तरह से इसे string::substr
लागू किया गया है और जिस तरह से लागू किया गया है, उसके लिए चेक की ज़रूरत नहीं है । ए)string::npos
"लंबाई" के रूप में पारित किया गया है => substr
अंत तक सभी पढ़ने के व्यवहार को प्रलेखित किया है। ख) substr
दिया जाता है " string::npos + 1
": और कोई लंबाई string::npos
के एक मूल्य के लिए प्रलेखित है -1
करने के लिए मूल्यांकन करता है ताकि, 0
=> स्ट्रिंग के शुरू करने और लंबाई 'डिफ़ॉल्ट मान के लिए substr
है npos
=> पर काम करता है "सिर्फ फ़ाइल नाम" भी cplusplus.com/reference / string / string / substr cplusplus.com/reference/string/string/npos
C ++ 11 संस्करण (जेम्स Kanze के संस्करण से प्रेरित) वर्दी इनिशियलाइज़ेशन और अनाम इनलाइन लैम्ब्डा के साथ।
std::string basename(const std::string& pathname)
{
return {std::find_if(pathname.rbegin(), pathname.rend(),
[](char c) { return c == '/'; }).base(),
pathname.end()};
}
हालांकि यह फ़ाइल एक्सटेंशन को नहीं हटाता है।
return c == '/' || c == '\\';
खिड़कियों पर यह काम करने के लिए
if (pathname.size() == 0) return "."; auto iter = pathname.rbegin(); auto rend = pathname.rend(); while (iter != rend && *iter == '/') ++iter; if (iter == rend) /* pathname has only path separators */ return "/"; pathname = std::string(pathname.begin(), iter.base());
boost
filesystem
पुस्तकालय के रूप में भी उपलब्ध है experimental/filesystem
पुस्तकालय और सी ++ 17 के लिए ++ आईएसओ सी में विलय हो गया। आप इसे इस तरह से उपयोग कर सकते हैं:
#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 *, वीएस एंटरप्राइज 2015 के साथ काम नहीं करता है
_splitpath ने भी काम किया, लेकिन मुझे यह अनुमान लगाना पसंद नहीं है कि मुझे कितने चार [?] वर्णों की आवश्यकता है; कुछ लोगों को शायद इस नियंत्रण की आवश्यकता है, मुझे लगता है।
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 के लिए आवश्यक थे। इन समाधानों के लिए किसी बाहरी पुस्तकालयों (जैसे बढ़ावा) की आवश्यकता नहीं थी।
मैं इसे करूँगा ...
जब तक आप पहले बैकस्लैश / फ़ॉरवर्ड स्लैश नहीं पाते, तब तक स्ट्रिंग के अंत से पीछे की ओर खोजें।
तब स्ट्रिंग के अंत से फिर से पीछे की ओर खोजें जब तक आप पहली डॉट (।) नहीं पाते।
तब आपके पास फ़ाइल नाम का प्रारंभ और अंत होता है।
साधारण ...
'\\'
पथ विभाजक के रूप में स्वीकार करता है वह भी उपयोग करता है '/'
, इसलिए आपको या तो मिलान करने की आवश्यकता है।) और मुझे यकीन नहीं है कि आप क्या देख रहे हैं।
my.source.cpp
संकलित हो जाता है । my.source.obj
.cpp
.obj
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 में फ़ाइल नाम है।
boost::filesystem::path( path ).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 आदि प्रदान करते हैं। और निश्चित रूप से यह क्रॉस पट्टिका भी है।
getFilename
या कुछ इस तरह से एन्क्रिप्ट करें)।
आप इसे बहुत अच्छी तरह से करने के लिए std :: filesystem का उपयोग कर सकते हैं:
#include <filesystem>
namespace fs = std::experimental::filesystem;
fs::path myFilePath("C:\\MyDirectory\\MyFile.bat");
fs::path filename = myFilePath.stem();
लंबे समय से मैं एक फ़ंक्शन की तलाश कर रहा था जो फ़ाइल पथ को ठीक से विघटित करने में सक्षम हो। मेरे लिए यह कोड लिनक्स और विंडोज दोनों के लिए पूरी तरह से काम कर रहा है।
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 नहीं है तो । यदि आप एक परिवाद लिख रहे हैं, तो आपके कोड का उपयोग किसी भी परियोजना में किया जा सकता है, जिसमें यूआई नहीं है।
यदि आप ऐसा कोड लिख रहे हैं जो किसी उपयोगकर्ता द्वारा लॉग इन नहीं किया जाता है (जैसे सेवा [या अन्य] बूट या स्टार्टअप पर शुरू करने के लिए सेट) तो कोई नहीं है HKCU
। अंत में, शलवापी निपटान कार्य हैं; और विंडोज के बाद के संस्करणों में पदावनत करने के लिए सूची में उच्च परिणाम के रूप में।
मैंने एक फ़ंक्शन लागू किया जो आपकी आवश्यकताओं को पूरा कर सकता है। यह string_view के कॉन्स्ट्रेक्स फंक्शन find_last_of (c ++ 17 के बाद से) पर आधारित है, जिसकी गणना समान समय पर की जा सकती है
constexpr const char* base_filename(const char* p) {
const size_t i = std::string_view(p).find_last_of('/');
return std::string_view::npos == i ? p : p + i + 1 ;
}
//in the file you used this function
base_filename(__FILE__);