Pobieranie nazwy katalogu z nazwy pliku


85

Mam nazwę pliku (C: \ folder \ foo.txt) i muszę pobrać nazwę folderu (C: \ folder) w niezarządzanym C ++. W C # zrobiłbym coś takiego:

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

Czy istnieje funkcja, której można użyć w niezarządzanym C ++ do wyodrębnienia ścieżki z nazwy pliku?

Odpowiedzi:


20

Jest do tego standardowa funkcja Windows, PathRemoveFileSpec . Jeśli obsługujesz tylko system Windows 8 i nowsze, zdecydowanie zaleca się użycie zamiast tego PathCchRemoveFileSpec . Oprócz innych ulepszeń, nie jest już ograniczony do MAX_PATH(260) znaków.


2
Zauważ, że ta funkcja jest obecnie przestarzała. Sugestią firmy Microsoft jest użycie zamiast tego PathCchRemoveFileSpec .
Domyślnie

1
@Default: PathCchRemoveFileSpec jest dostępne tylko począwszy od systemu Windows 8. Ponieważ systemy Windows Vista i 7 są nadal obsługiwane, tak samo jest z parametrami PathRemoveFileSpec .
Niespodziewane

153

Korzystanie z Boost.Filesystem:

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

2
p.remove_filename()zmodyfikuje pna miejscu i może być wdrożony wydajniej niżp = p.parent_path()
Peter Cordes,

Jeśli możesz również zajmować się katalogami, pamiętaj, że parent_path()from "C:\\folder"spowoduje rozszerzenie "C:".
Semjon Mössinger

wiele ulepszeń zostanie zaktualizowanych do standardowego, więc spróbuj też tego .... dołącz <system plików> .... std :: eksperyment :: system plików :: ścieżka p ("C: \\ folder \\ foo.txt");
S Meaden

72

Przykład z 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
To najlepsze minimalne rozwiązanie tutaj.
plasmacel

39

W C ++ 17 istnieje klasa std::filesystem::pathkorzystająca z metody 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';
}

Możliwe wyjście:

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"

2
Istnieje również .remove_filename()metoda.
Qqwy

1
Dzięki @Qqwy, pozwala również na użycie ścieżki katalogu z tą metodą, aby uzyskać poprawne i oczekiwane wyniki w przeciwieństwie do podejścia z odpowiedzi
Herrgott

13

Dlaczego to musi być takie skomplikowane?

#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
To nie jest przenośne. Separatorem ścieżek w Linuksie jest „/”. std :: filesystem :: path jest standardowe i przenośne.
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

Może być konieczne p.parent_path().filename()uzyskanie nazwy folderu nadrzędnego.


5

Użyj boost :: filesystem. I tak zostanie włączony do następnego standardu, więc równie dobrze możesz się do niego przyzwyczaić.


1
O jakim standardzie mówisz? Wiem, że wiele rzeczy z boosta zostało dodanych do C ++ std lib, system plików też zostanie dodany?
McLeary,

7
„I tak zostanie włączony do następnego standardu”. I tak nie jest
Anton K.

@AntonK może C ++ 2017?
Alessandro Jacopson

6
@AlessandroJacopson Cool, wydaje się być zawarty w C ++ 17 - en.cppreference.com/w/cpp/filesystem
Anton K


1

Jestem tak zaskoczony, że nikt nie wspomniał o standardowym sposobie w Posix

Użyj basename / dirnamekonstrukcji.

mężczyzna basename


Funkcje POSIX nie są pozbawione wad. W szczególności mogą modyfikować bufor, który przekazujesz (naprawdę mają na myśli, że podpis jest, basname(char * path)a nie basename(const char * path)), a implementacje, które tego nie robią, wydają się używać bufora statycznego, co czyni je niebezpiecznymi wątkowo (w zasadzie może również zwrócić dynamicznie przydzielane wyniki, ale to uzależnia od allocfunkcji rodzinnych, co jest niewygodne w C ++).
dmckee --- kociak byłego moderatora

-1

Standardowy C ++ nie zrobi zbyt wiele w tym zakresie, ponieważ nazwy ścieżek są specyficzne dla platformy. Możesz ręcznie przeanalizować ciąg (jak w odpowiedzi glowcodera), skorzystać z udogodnień systemu operacyjnego (np. Http://msdn.microsoft.com/en-us/library/aa364232(v=VS.85).aspx ) lub prawdopodobnie Najlepszym podejściem jest użycie biblioteki systemu plików innej firmy, takiej jak boost :: filesystem.


Standardowy C ++ 1z obecnie próbuje zaadoptować bibliotekę systemu plików boost, co sprawia, że ​​przyjazność dla platformy jest znacznie mniejszym problemem. Przynajmniej nadal znajduje się w eksperymentalnych nagłówkach MSVC.
kayleeFrye_onDeck

-6

Po prostu użyj tego: ExtractFilePath (your_path_file_name)


5
Uważam, że jest to metoda Delphi, a nie coś w C ++.
Ian Hunter
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.