एक पथ से एक फ़ाइल नाम प्राप्त करें


85

एक पथ से फ़ाइल नाम प्राप्त करने का सबसे सरल तरीका क्या है?

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

इस उदाहरण में, मुझे "MyFile" मिलना चाहिए। बिना विस्तार के।


1
जब तक आप बैकस्पेस नहीं मारते तब तक पीछे से खोजें?
केरेक एसबी

2
@KerrekSB, आपका मतलब है बैकस्लैश ;)
निम

मेरे पास एक std :: string है जिसमें एक फ़ाइल "c: \\ MyDirectory \\ Myfile.pdf" का पथ है, मुझे इस फ़ाइल को myfile_md.pdf में फिर से नाम देने की आवश्यकता है ताकि मुझे पथ से फ़ाइल नाम प्राप्त करने की आवश्यकता हो।
निर्दल


2
@ नी: हाँ! मैं बाहर जा रहा हूँ ...
केआरके एसबी

जवाबों:


29

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

2
_splitpathमेरी मशीन में कोई भी शामिल नहीं है।
जेम्स कान्जे

9
मेरे पास Visual Studio, और g ++ और Sun CC है। जब पूरी तरह से अच्छे पोर्टेबल समाधान होते हैं तो मुझे कुछ गैर-मानक का उपयोग क्यों करना चाहिए।
जेम्स कांजे

2
@ नाम, यह कहने के लिए जुड़ा हुआ पृष्ठ है <stdlib.h>। पोर्टेबिलिटी के लिए, शायद आप "पूरी तरह से अच्छा पोर्टेबल समाधान" के कुछ उदाहरणों को सूचीबद्ध कर सकते हैं?
Synetech

2
@Synetech एक Microsoft एक्सटेंशन का वर्णन करने के लिए जुड़ा हुआ पृष्ठ, नहीं <stdlib.h>। और स्पष्ट स्पष्ट पोर्टेबल समाधान है boost::filesystem
बजे जेम्स कान्ज़

3
@James, आप की जरूरत नहीं है _splitpathमें stdlib.hवी.एस. की अपनी प्रतिलिपि की? तब आप VS की मरम्मत स्थापित करना चाहते हैं।
19

63

एक संभावित समाधान:

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

सबसे सरल हमेशा सबसे अच्छा है!
जीन फ़्राँस्वा Fabre

61

कार्य काफी सरल है क्योंकि आधार फ़ाइल नाम फ़ोल्डर के लिए अंतिम परिधि में शुरू होने वाले स्ट्रिंग का हिस्सा है:

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

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

इस उपयोग के मामले में सब कुछ ठीक है (और मूल प्रश्न का उत्तर दिया गया है), लेकिन आपका एक्सटेंशन रिमूवर सही नहीं है - यह विफल हो जाएगा अगर हम "
/home/user/my.dir/myfile

@avtomaton एक्सटेंशन हटाने वाले फ़ंक्शन का उपयोग फ़ाइल नाम पर किया जाना चाहिए, पथ नहीं। (बस base_nameपहले आवेदन करें ।)
Pixelchemist

मैं इसे समझता हूं (इसलिए मैंने लिखा है कि मूल प्रश्न का उत्तर दिया गया है और इस उपयोग-मामले में सब कुछ ठीक है)। बस इस मुद्दे को किसी ऐसे व्यक्ति के लिए इंगित करना चाहता था जो इन स्निपेट्स का उपयोग करने की कोशिश करेगा।
avtomaton

बहुत अच्छी व्याख्या। यह समस्या की संरचनात्मक समझ को बढ़ाता है। धन्यवाद
hell_ical_vortex

38

सबसे सरल उपाय कुछ का उपयोग करना है 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 );
}

कोड थोड़ा अधिक जटिल है, क्योंकि इस मामले में, रिवर्स पुनरावृत्ति का आधार गलत पक्ष पर है जहां हम कटौती करना चाहते हैं। (याद रखें कि रिवर्स इटरेटर का आधार चरित्र के पीछे एक है जो इट्रेटर इंगित करता है।) और यहां तक ​​कि यह थोड़ा संदिग्ध है: मुझे इस तथ्य को पसंद नहीं है कि यह खाली स्ट्रिंग लौटा सकता है, उदाहरण के लिए। (यदि केवल '.'फ़ाइल नाम का पहला वर्ण है, तो मेरा तर्क है कि आपको पूरा फ़ाइल नाम वापस करना चाहिए। विशेष मामले को पकड़ने के लिए थोड़ा अतिरिक्त कोड की आवश्यकता होगी।)}


9
कैसे string::find_last_ofरिवर्स पुनरावृत्तियों में हेरफेर करने के बजाय उपयोग करने के बारे में ?
ल्यूक टॉरिल

@LucTouraille जब कोई काम करेगा तो दो तरीके क्यों सीखेंगे? आपको छोड़कर किसी भी कंटेनर के लिए पुनरावृत्तियों की आवश्यकता होगी string, इसलिए आपको उन्हें वैसे भी सीखना होगा। और उन्हें सीखा, फूला हुआ इंटरफ़ेस के सभी सीखने के लिए परेशान करने का कोई कारण नहीं है std::string
बजे जेम्स कान्जे

नोट: विज़ुअल स्टूडियो 2015 और इसके बाद वाले <filesystem> हेडर जहाज, ताकि आपको इसका उपयोग करने के लिए बढ़ावा देने पर निर्भरता न बढ़ानी पड़े।
IInspectable

16

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


यह अब "प्रायोगिक" में नहीं है
विट

15

आप शेल पाथ 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 से लिंक करना होगा, लेकिन मुझे वास्तव में यकीन नहीं है कि यह खामी क्यों है।


एक मार्ग से फ़ाइल नाम प्राप्त करने के लिए मेरा पसंदीदा समाधान।
एंड्रियास

15

यदि आप बूस्ट का उपयोग कर सकते हैं,

#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(रेफरी। उबंटू पर बढ़ावा कैसे स्थापित करें? ) द्वारा बूस्ट लाइब्रेरी स्थापित कर सकते हैं ।


12

समारोह:

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

8

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अगर कुछ भी नहीं मिला था।
कोन्गुसबोंगस

@congusbongus सच है, लेकिन फ़ाइल पथ को विभाजित करने का कोई मतलब नहीं है जब यह सिर्फ एक फ़ाइल नाम है (पथ के बिना) :)
jave.web

@ jave.web यह समझ में आता है और MUST 'स्ट्रिंग :: npos' रिटर्न संभालता है। इसके लिए एक फ़ंक्शन को लागू करना "बस फ़ाइलनाम" सहित विभिन्न इनपुट को संभालने में सक्षम होना चाहिए। अन्यथा, वास्तविक कार्यान्वयन में इसकी छोटी गाड़ी होने पर यह बेकार हो जाएगा।
winux

@winux यह पहले से ही मानता है मान्य के रास्ते ... आप इनपुट पर भरोसा नहीं करते हैं, तो आप निश्चित रूप से, पथ पहले सत्यापित करना चाहिए।
jave.web

@विनक्स वैसे भी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
jave.web

5

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

हालांकि यह फ़ाइल एक्सटेंशन को नहीं हटाता है।


छोटा और मीठा, हालांकि यह केवल गैर-विंडोज पथ के साथ काम करता है।
Volomike

तुम हमेशा return c == '/' || c == '\\';खिड़कियों पर यह काम करने के लिए
भेड़ का बच्चा

"", "///", और "dir1 / dir2 /" जैसे रास्तों को संभालने के लिए, ऊपर दिए गए विवरण से पहले निम्न कोड जोड़ें (cf. POSIX basename ()): 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());
Gidfiddle

5

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वस्तुओं के लिए भी काम करता है ।


4

यह केवल एक चीज है जो वास्तव में मेरे लिए काम करती है:

#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 के लिए आवश्यक थे। इन समाधानों के लिए किसी बाहरी पुस्तकालयों (जैसे बढ़ावा) की आवश्यकता नहीं थी।


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

3

मैं इसे करूँगा ...

जब तक आप पहले बैकस्लैश / फ़ॉरवर्ड स्लैश नहीं पाते, तब तक स्ट्रिंग के अंत से पीछे की ओर खोजें।

तब स्ट्रिंग के अंत से फिर से पीछे की ओर खोजें जब तक आप पहली डॉट (।) नहीं पाते।

तब आपके पास फ़ाइल नाम का प्रारंभ और अंत होता है।

साधारण ...


मुझे पता है कि किसी भी प्रणाली के लिए काम नहीं करता है। (एक सिस्टम जो '\\'पथ विभाजक के रूप में स्वीकार करता है वह भी उपयोग करता है '/', इसलिए आपको या तो मिलान करने की आवश्यकता है।) और मुझे यकीन नहीं है कि आप क्या देख रहे हैं।
जेम्स कान्जे

ठीक है, इसलिए इसे या तो मैच करने के लिए संशोधित करें, कोई बड़ी बात नहीं। और पहले डॉट (।) के लिए आगे देख रहे हैं
टॉमपी89

आपको अभी भी अंतिम बिंदु ढूंढना है, पहले नहीं। (उल्टे
चलने वाले

आह हाँ, अच्छी बात है। तो एक file.ext.ext के लिए तब आप file.ext निकालना चाहेंगे आप नहीं करेंगे। :)
टॉमपी

मुमकिन है। यह सामान्य सम्मेलन है, किसी भी मामले में: उदाहरण के लिए (विस्तार के साथ प्रतिस्थापित ) के लिए my.source.cppसंकलित हो जाता है । my.source.obj.cpp.obj
जेम्स कंज

2
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 में फ़ाइल नाम है।


3
वाह - यह पथ से "फ़ाइल नाम प्राप्त करें" के लिए बहुत कोड है ... :)
निम

4
@ मेरी छाप भी। अपने स्वयं के कोड में, मैं एक-लाइनर का उपयोग करता हूं boost::filesystem::path( path ).filename():।
जेम्स कान्जे

मेरे पास एक CFileInfo वर्ग है जिसमें वह कोड है। मैंने यहां सिर्फ कोड डंप किया क्योंकि यह परीक्षण किया गया है और मैं कुछ भी जोखिम नहीं लेना चाहता था ... आप इस उदाहरण से कोड की लगभग 5 पंक्तियों का उपयोग कर सकते हैं।
लुकियन

2

उपयोग न करें _splitpath()और_wsplitpath() । वे सुरक्षित नहीं हैं, और वे अप्रचलित हैं!

इसके बजाय, उनके सुरक्षित संस्करणों का उपयोग करें, अर्थात् _splitpath_s()और_wsplitpath_s()


2

यह भी काम करना चाहिए:

// 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 आदि प्रदान करते हैं। और निश्चित रूप से यह क्रॉस पट्टिका भी है।


4
अपने कोड के भविष्य के पाठकों की खातिर, कृपया कोड के एक ही लाइन में सब कुछ भरने के बजाय सार्थक नामों के साथ अस्थायी चर का उपयोग करें (और जब आप इस पर हों, तो कृपया इस सब को एक फ़ंक्शन getFilenameया कुछ इस तरह से एन्क्रिप्ट करें)।
ल्यूक टॉरिल

संपादित। लेकिन बिंदु इसे छोटा करने के लिए था, क्योंकि पहले से ही कई काम के जवाब दिए गए हैं।
typedef

1
मुझे लगता है कि यह गलत है। क्या आपको अंतिम भाग: "strPath.size () - strPath.find_last_of (" "") को "strPath.find_last_of (" "") द्वारा प्रतिस्थापित नहीं करना चाहिए - iLastSeparator
taktak004

@ taktak004 आप सही हैं, यह `रिटर्न strPath.substr (iLastSeparator = strPath.find_last_of (" / ") होना चाहिए! = std :: string :: npos? iLastSeparator + 1: 0, strPath.find_last_of ("? ") ) - iLastSeparator); `
फिनमॉड

2

आप इसे बहुत अच्छी तरह से करने के लिए std :: filesystem का उपयोग कर सकते हैं:

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

fs::path myFilePath("C:\\MyDirectory\\MyFile.bat");
fs::path filename = myFilePath.stem();

0

लंबे समय से मैं एक फ़ंक्शन की तलाश कर रहा था जो फ़ाइल पथ को ठीक से विघटित करने में सक्षम हो। मेरे लिए यह कोड लिनक्स और विंडोज दोनों के लिए पूरी तरह से काम कर रहा है।

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:  ''

मुझे आशा है कि इससे आपको भी मदद मिलेगी :)


0

shlwapi.lib/dllHKCUआंतरिक रूप से रजिस्ट्री हाइव का उपयोग करता है ।

इससे लिंक नहीं करना सबसे अच्छा है shlwapi.libयदि आप लाइब्रेरी बना रहे हैं या उत्पाद में UI नहीं है तो । यदि आप एक परिवाद लिख रहे हैं, तो आपके कोड का उपयोग किसी भी परियोजना में किया जा सकता है, जिसमें यूआई नहीं है।

यदि आप ऐसा कोड लिख रहे हैं जो किसी उपयोगकर्ता द्वारा लॉग इन नहीं किया जाता है (जैसे सेवा [या अन्य] बूट या स्टार्टअप पर शुरू करने के लिए सेट) तो कोई नहीं है HKCU। अंत में, शलवापी निपटान कार्य हैं; और विंडोज के बाद के संस्करणों में पदावनत करने के लिए सूची में उच्च परिणाम के रूप में।


0

एक धीमी लेकिन सीधे आगे रेगेक्स समाधान:

    std::string file = std::regex_replace(path, std::regex("(.*\\/)|(\\..*)"), "");

0

मैंने एक फ़ंक्शन लागू किया जो आपकी आवश्यकताओं को पूरा कर सकता है। यह 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__);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.