2010-06-18 17 views
61

Ho un nome file (C: \ folder \ foo.txt) e ho bisogno di recuperare il nome della cartella (C: \ cartella) in C++ non gestito. In C# vorrei fare qualcosa di simile:Ottenere un nome di directory da un nome file

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

C'è una funzione che può essere utilizzato in C++ non gestito per estrarre il percorso dal nome del file?

+1

Utilizzi Boost? – AraK

+2

Ovviamente è banale scrivere una tale funzione, ma è ancora meglio usare una funzione della libreria standard del linguaggio di programmazione o dell'API del sistema operativo. –

+1

Non sto usando boost in questo progetto, mi dispiace. –

risposta

18

V'è una funzione standard di Windows per questo, PathRemoveFileSpec. Se si supporta solo Windows 8 e versioni successive, si consiglia vivamente di utilizzare PathCchRemoveFileSpec. Tra gli altri miglioramenti, non è più limitato ai caratteri MAX_PATH (260).

+1

Si noti che questa funzione è ora obsoleta. Il suggerimento di Microsoft è quello di utilizzare [PathCchRemoveFileSpec] (https://msdn.microsoft.com/en-us/library/hh707092%28v=vs.85%29.aspx). – Default

+1

@Default: [PathCchRemoveFileSpec] (https://msdn.microsoft.com/en-us/library/hh707092.aspx) è disponibile solo a partire da Windows 8. Poiché Windows Vista e 7 sono ancora supportati, lo stesso vale per [PathRemoveFileSpec] (https://msdn.microsoft.com/en-us/library/bb773748.aspx). – IInspectable

44

Esempio da 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++ non farà molto per voi in questo senso, dal momento che i nomi di percorso sono specifici per la piattaforma. È possibile analizzare manualmente la stringa (come nella risposta di glowcoder), utilizzare le funzioni del sistema operativo (ad esempio http://msdn.microsoft.com/en-us/library/aa364232(v=VS.85).aspx) o, probabilmente, l'approccio migliore, è possibile utilizzare una libreria di file system di terze parti come boost :: filesystem.

+0

Il C++ 1z dello standard sta attualmente tentando di adottare la libreria di boost del filesystem, rendendo la piattaforma molto meno problematica. Almeno è ancora nelle intestazioni sperimentali per MSVC. –

4

Usa boost :: filesystem. Sarà comunque incorporato nel prossimo standard in modo da poterci abituare.

+1

Di quale norma stai parlando? So che un sacco di cose da boost sono stati aggiunti a C++ std lib, verrà aggiunto anche il filesystem? – McLeary

+6

"Sarà comunque incorporato nel prossimo standard" E non è –

+1

@AntonK è in tr2 – CoffeeandCode

121

Utilizzando Boost.Filesystem:

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

'p.remove_filename() 'modificherà' p' sul posto e [potrebbe essere implementato in modo più efficiente di 'p = p.parent_path()'] (http://www.boost.org/doc/libs/1_60_0/libs/ filesystem/doc/reference.html # path-remove_filename) –

+0

Se si può anche trattare con le directory essere consapevoli del fatto che 'parent_path()' da '" C: \\ cartella "' risulterà in '" C: "' . –

+0

un sacco di boost viene aggiornato a std quindi prova anche questo .... include .... std :: experimental :: filesystem :: path p ("C: \\ folder \\ foo.txt"); –

-3

Basta usare questo: ExtractFilePath (your_path_file_name)

+4

Credo che questo sia un metodo Delphi, non qualcosa in C++. –

5

Perché deve essere così complicato?

#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

Secondo cppreference.com, esiste supporto sperimentale libreria di intestazione per C++ 17/1z con la classe std::experimental::filesystem::path utilizzando il metodo 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'; 
} 

uscita possibile:

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

Sono così sorpreso nessuno ha menzionato il modo standard in Posix

Utilizzare basename/dirname costrutti.

man basename

Problemi correlati