2010-06-18 5 views
61

Ich habe einen Dateinamen (C: \ folder \ foo.txt) und ich muss den Ordnernamen (C: \ Ordner) in nicht verwaltetem C++ abrufen. In C# würde ich so etwas tun:Abrufen eines Verzeichnisnamens aus einem Dateinamen

string folder = new FileInfo("C:\folder\foo.txt").DirectoryName; 

Gibt es eine Funktion, die in nicht verwalteten C++ verwendet werden kann, aus dem Dateinamen den Pfad zu extrahieren?

+1

Haben Sie boost? – AraK

+2

Natürlich ist es trivial, eine solche Funktion selbst zu schreiben, aber es ist sogar besser, eine Funktion der Standardbibliothek der Programmiersprache oder der API des Betriebssystems zu verwenden. –

+1

Ich benutze keinen Boost in diesem Projekt, sorry. –

Antwort

18

Es ist ein Standard-Windows-Funktion für diese, PathRemoveFileSpec. Wenn Sie nur Windows 8 und höher unterstützen, wird dringend empfohlen, stattdessen PathCchRemoveFileSpec zu verwenden. Neben anderen Verbesserungen ist es nicht mehr auf MAX_PATH (260) Zeichen beschränkt.

+1

Beachten Sie, dass diese Funktion jetzt veraltet ist. Der Vorschlag von Microsoft ist stattdessen [PathCchRemoveFileSpec] (https://msdn.microsoft.com/en-us/library/hh707092%28v=vs.85%29.aspx) zu verwenden. – Default

+1

@Default: [PathCchRemoveFileSpec] (https://msdn.microsoft.com/en-us/library/hh707092.aspx) ist nur ab Windows 8 verfügbar. Da Windows Vista und 7 weiterhin unterstützt werden, ist auch [PathRemoveFileSpec] (https://msdn.microsoft.com/en-us/library/bb773748.aspx). – IInspectable

44

Beispiel von http://www.cplusplus.com/reference/string/string/find_last_of/

// string::find_last_of 
#include <iostream> 
#include <string> 
using namespace std; 

void SplitFilename (const string& str) 
{ 
    size_t found; 
    cout << "Splitting: " << str << endl; 
    found=str.find_last_of("/\\"); 
    cout << " folder: " << str.substr(0,found) << endl; 
    cout << " file: " << str.substr(found+1) << endl; 
} 

int main() 
{ 
    string str1 ("/usr/bin/man"); 
    string str2 ("c:\\windows\\winhelp.exe"); 

    SplitFilename (str1); 
    SplitFilename (str2); 

    return 0; 
} 
1

Standard C++ wird in dieser Hinsicht für Sie nicht viel tun, da Pfadnamen plattformspezifisch sind. Sie können die Zeichenfolge manuell analysieren (wie in der Antwort von glowcoder), Betriebssystemfunktionen verwenden (z. B. http://msdn.microsoft.com/en-us/library/aa364232(v=VS.85).aspx), oder wahrscheinlich die beste Methode, Sie können eine Dateisystembibliothek eines Drittanbieters wie boost :: filesystem verwenden.

+0

Das C++ 1z des Standards versucht derzeit, die Boost-Dateisystem-Bibliothek zu übernehmen, wodurch die Plattformfreundlichkeit nun viel weniger problematisch wird. Es ist immer noch in den experimentellen Headern für MSVC. –

4

Verwenden Sie boost :: Dateisystem. Es wird sowieso in den nächsten Standard aufgenommen, damit Sie sich auch daran gewöhnen können.

+1

Welchen Standard sprechen Sie? Ich weiß, dass viele Dinge von Boost in C++ Std Lib hinzugefügt wurden, Dateisystem wird auch hinzugefügt werden? – McLeary

+6

"Es wird sowieso in den nächsten Standard aufgenommen werden" Und es ist nicht –

+1

@AntonK es ist in tr2 – CoffeeandCode

121

Mit Boost.Filesystem:

boost::filesystem::path p("C:\\folder\\foo.txt"); 
boost::filesystem::path dir = p.parent_path(); 
+2

'p.remove_filename() 'modifiziert 'p' direkt und [kann effizienter implementiert werden als' p = p.parent_path() '] (http://www.boost.org/doc/libs/1_60_0/libs/ filesystem/doc/reference.html # path-remove_filename) –

+0

Wenn Sie auch mit Verzeichnissen umgehen können, beachten Sie, dass 'parent_path()' aus '" C: \\ folder "' zu '" C: "' führt . –

+0

viele Boost wird auf STD aktualisiert so versuchen Sie auch dies .... einschließlich .... std :: experimental :: filesystem :: Pfad p ("C: \\ Ordner \\ foo.txt"); –

-3

Nur diese verwenden: ExtractFilePath (your_path_file_name)

+4

Ich glaube, das ist eine Delphi-Methode, nicht etwas in C++. –

5

Warum ist es so kompliziert sein?

#include <windows.h> 

int main(int argc, char** argv)   // argv[0] = C:\dev\test.exe 
{ 
    char *p = strrchr(argv[0], '\\'); 
    if(p) p[0] = 0; 

    printf(argv[0]);     // argv[0] = C:\dev 
} 
3

Nach cppreference.com, experimental Headers Bibliotheksunterstützung besteht für C++ 17/1Z mit der Klasse std::experimental::filesystem::path unter Verwendung des Verfahrens parent_path.

#include <iostream> 
#include <experimental/filesystem> 
namespace fs = std::experimental::filesystem; 
int main() 
{ 
    for(fs::path p : {"/var/tmp/example.txt", "/", "/var/tmp/."}) 
     std::cout << "The parent path of " << p 
        << " is " << p.parent_path() << '\n'; 
} 

Mögliche Ausgabe:

The parent path of "/var/tmp/example.txt" is "/var/tmp" 
The parent path of "/" is "" 
The parent path of "/var/tmp/." is "/var/tmp" 
0

Ich bin überrascht, so dass niemand die Standardmethode in Posix erwähnt

Bitte verwenden basename/dirname Konstrukte.

Mann Basisnamen