Ottenere un nome di directory da un nome di file


85

Ho un nome file (C: \ cartella \ foo.txt) e devo recuperare il nome della cartella (C: \ cartella) in C ++ non gestito. In C # farei qualcosa del genere:

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

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

Risposte:


20

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


2
Tieni presente che questa funzione è ora deprecata. Il suggerimento di Microsoft è di utilizzare invece PathCchRemoveFileSpec .
Predefinito

1
@Default: PathCchRemoveFileSpec è disponibile solo a partire da Windows 8. Poiché Windows Vista e 7 sono ancora supportati, lo è anche PathRemoveFileSpec .
Rilevabile

154

Utilizzando Boost.Filesystem:

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


Se hai a che fare anche con le directory sii consapevole del fatto che parent_path()da "C:\\folder"risulterà in "C:".
Semjon Mössinger

molti boost vengono aggiornati a std quindi prova anche questo .... includi <filesystem> .... std :: experiment :: filesystem :: path p ("C: \\ folder \\ foo.txt");
S Meaden

72

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
Questa è la migliore soluzione minima qui.
plasmacel

42

In C ++ 17 esiste una classe che std::filesystem::pathutilizza il metodo parent_path.

#include <iostream>
#include <filesystem>
namespace fs = std::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';
}

Possibile output:

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"

3
Esiste anche un .remove_filename()metodo.
Qqwy

1
Grazie, @Qqwy, consente anche di utilizzare il percorso della directory con quel metodo per ottenere risultati corretti e attesi a differenza dell'approccio della risposta
Herrgott

13

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
}

10
Questo non è portatile. Il separatore di percorso in Linux è "/". std :: filesystem :: path è standard e portabile.
Rémi

7
 auto p = boost::filesystem::path("test/folder/file.txt");
 std::cout << p.parent_path() << '\n';             // test/folder
 std::cout << p.parent_path().filename() << '\n';  // folder
 std::cout << p.filename() << '\n';                // file.txt

Potrebbe essere necessario p.parent_path().filename()ottenere il nome della cartella principale.


5

Usa boost :: filesystem. Sarà comunque incorporato nel prossimo standard, quindi potresti anche abituarti.


1
Di quale standard parli? So che molte cose da boost sono state aggiunte a C ++ std lib, verrà aggiunto anche il filesystem?
McLeary

7
"Sarà comunque incorporato nel prossimo standard" E non lo è
Anton K

@AntonK forse C ++ 2017?
Alessandro Jacopson

6
@AlessandroJacopson Cool, sembra incluso in C ++ 17 - en.cppreference.com/w/cpp/filesystem
Anton K


1

Sono così sorpreso che nessuno abbia menzionato il modo standard in Posix

Per favore usa i basename / dirnamecostrutti.

uomo basename


1
Le funzioni POSIX non sono prive di inconvenienti. In particolare possono modificare il buffer che si passa (in realtà significano che la firma lo è basname(char * path)e non lo è basename(const char * path)), e le implementazioni che non lo fanno sembrano dover utilizzare un buffer statico che le rende non sicure per i thread (in linea di principio tu potrebbe anche restituire risultati allocati dinamicamente, ma ciò ti rende dipendente dalle allocfunzioni familiari che è scomodo in C ++).
dmckee --- gattino ex moderatore

-1

Il C ++ standard non farà molto per te a questo proposito, poiché i nomi dei percorsi sono specifici della piattaforma. È possibile analizzare manualmente la stringa (come nella risposta di glowcoder), utilizzare le funzionalità del sistema operativo (ad esempio http://msdn.microsoft.com/en-us/library/aa364232(v=VS.85).aspx ) o probabilmente il approccio migliore, puoi usare una libreria di file system di terze parti come boost :: filesystem.


Il C ++ 1z dello standard sta attualmente tentando di adottare la libreria del filesystem boost fin da ora rendendo la compatibilità con la piattaforma molto meno un problema. Almeno, è ancora nelle intestazioni sperimentali per MSVC.
kayleeFrye_onDeck

-6

Usa questo: ExtractFilePath (your_path_file_name)


5
Credo che questo sia un metodo Delphi, non qualcosa in C ++.
Ian Hunter,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.