Die Boost C++ Bibliotheken

Pfadangaben

Die Klasse boost::filesystem::path ist die zentrale Klasse in Boost.Filesystem. Sie repräsentiert Pfadangaben und bietet zahlreiche Methoden an, um Pfadangaben zu verarbeiten.

Die Headerdatei, die Sie zur Verarbeitung von Pfadangaben einbinden müssen, ist boost/filesystem.hpp. Alle von Boost.Filesystem angebotenen Klassen und Funktionen befinden sich im Namensraum boost::filesystem.

Sie können Pfadangaben bilden, indem Sie die Klasse boost::filesystem::path wie im Beispiel 35.1 mit einem entsprechenden String initialisieren.

Beispiel 35.1. boost::filesystem::path in Aktion
#include <boost/filesystem.hpp>

using namespace boost::filesystem;

int main()
{
  path p1{"C:\\"};
  path p2{"C:\\Windows"};
  path p3{L"C:\\Boost C++ \u5E93"};
}

Sie können boost::filesystem::path mit Wide-Strings initialisieren. Boost.Filesystem interpretiert Wide-Strings im Unicode-Format, so dass Pfadangaben erstellt werden können, die exotische Zeichen enthalten. Dies ist ein entscheidender Unterschied zum Vorgänger Boost.Filesystem 2, der mehrere Klassen wie boost::filesystem::path und boost::filesystem::wpath für unterschiedliche String-Typen anbot.

Beachten Sie, dass Boost.Filesystem keine Pfadangaben vom Typ std::u16string oder std::u32string unterstützt. Ihr Compiler bricht mit einer Fehlermeldung ab, wenn Sie versuchen, eine Pfadangabe von einem dieser String-Typen an den Konstruktor von boost::filesystem::path zu übergeben.

Die Konstruktoren von boost::filesystem::path überprüfen nicht, ob eine Pfadangabe Sinn ergibt und ob eine entsprechende Datei oder ein Verzeichnis existiert. Selbst mit offensichtlich unsinnigen Pfadangaben kann boost::filesystem::path instanziiert werden.

Beispiel 35.2. Unsinnige Pfadangaben mit boost::filesystem::path
#include <boost/filesystem.hpp>

using namespace boost::filesystem;

int main()
{
  path p1{"..."};
  path p2{"\\"};
  path p3{"@:"};
}

Beispiel 35.2 kann ohne Probleme ausgeführt werden, weil Pfadangaben letztendlich nur Strings sind. Die Klasse boost::filesystem::path macht nichts anderes als Strings zu verarbeiten. Es finden keine Zugriffe aufs Dateisystem statt.

Da boost::filesystem::path Strings verarbeitet, stehen Methoden bereit, um eine Pfadangabe als String zu erhalten. Interessanterweise stehen dazu eine ganze Reihe von Methoden zur Verfügung.

Boost.Filesystem unterscheidet grundsätzlich zwischen nativen und generischen Pfadangaben. Native Pfadangaben sind betriebssystemspezifisch und müssen verwendet werden, wenn zum Beispiel Betriebssystemfunktionen aufgerufen werden. Generische Pfadangaben sind portabel und betriebssystemunabhängig.

Beispiel 35.3. Pfadangaben von boost::filesystem::path als Strings erhalten
#include <boost/filesystem.hpp>
#include <iostream>

using namespace boost::filesystem;

int main()
{
  path p{"C:\\Windows\\System"};

#ifdef BOOST_WINDOWS_API
  std::wcout << p.native() << '\n';
#else
  std::cout << p.native() << '\n';
#endif

  std::cout << p.string() << '\n';
  std::wcout << p.wstring() << '\n';

  std::cout << p.generic_string() << '\n';
  std::wcout << p.generic_wstring() << '\n';
}

Die ersten drei aufgerufenen Methoden native(), string() und wstring() geben die Pfadangabe im nativen Format zurück. Wenn Sie Beispiel 35.3 unter Windows ausführen, wird dreimal C:\Windows\System ausgegeben – eine Pfadangabe, wie Sie unter Windows üblich ist.

Die letzten beiden aufgerufenen Methoden generic_string() und generic_wstring() geben die Pfadangabe im generischen Format zurück. Dabei handelt es sich um eine portable Pfadangabe – der String wird normalisiert. Die Regeln, nach denen generische Pfadangaben gebildet werden, entsprechen denen des POSIX-Standards. Generische Pfadangaben sind daher identisch mit Pfadangaben, wie sie beispielsweise unter Linux verwendet werden. So wird zum Beispiel als Trennzeichen für Verzeichnisse der Schrägstrich verwendet. Beispiel 35.3 unter Windows ausgeführt gibt für generic_string() und generic_wstring() C:/Windows/System aus.

Der Rückgabewert von Methoden für native Pfadangaben hängt davon ab, unter welchem Betriebssystem ein Programm ausgeführt wird. Der Rückgabewert von Methoden für generische Pfadangaben ist unabhängig vom Betriebssystem. Somit helfen generische Pfadangaben, plattformunabhängigen Code zu schreiben, da sie unabhängig vom Betriebssystem Dateien und Verzeichnisse eindeutig identifizieren.

Da boost::filesystem::path mit unterschiedlichen String-Typen initialisiert werden kann, werden entsprechend mehrere Methoden angeboten, um Pfadangaben in unterschiedlichen String-Typen zu erhalten. Während string() und generic_string() einen String vom Typ std::string zurückgeben, geben wstring() und generic_wstring() einen String vom Typ std::wstring zurück.

Der Typ des Rückgabewerts von native() hängt vom Betriebssystem ab, für das das Programm kompiliert wird. So gibt native() unter Windows einen String vom Typ std::wstring und unter Linux einen String vom Typ std::string zurück.

Beachten Sie, dass der Konstruktor von boost::filesystem::path sowohl generische als auch plattformabhängige Pfadangaben unterstützt. Die Angabe C:\\Windows\\System, die im obigen Programm verwendet wird, ist nicht portabel, sondern windows-spezifisch. Sie wird von Boost.Filesystem richtig interpretiert, wenn das Programm unter Windows ausgeführt wird. Das gleiche Programm auf einem POSIX-System wie Linux ausgeführt gibt für alle Methodenaufrufe C:\Windows\System zurück. Denn in diesem Fall erkennt Boost.Filesystem nicht, dass der Backslash als Trennzeichen für Dateien und Verzeichnisse verwendet werden soll: Er ist weder im portablen noch im nativen Format unter Linux ein Trennzeichen.

Das Makro BOOST_WINDOWS_API stammt aus Boost.System und ist definiert, wenn das Beispiel unter Windows kompiliert wird. Das entsprechende Makro für POSIX-Betriebssysteme lautet BOOST_POSIX_API.

Im Beispiel 35.4 findet die Initialisierung mit einem portablen Pfad statt.

Beispiel 35.4. boost::filesystem::path mit portablem Pfad initialisieren
#include <boost/filesystem.hpp>
#include <iostream>

using namespace boost::filesystem;

int main()
{
  path p{"/"};
  std::cout << p.string() << '\n';
  std::cout << p.generic_string() << '\n';
}

Da generic_string() einen portablen Pfad zurückgibt, ist das in diesem Fall genau die Angabe, mit der boost::filesystem::path initialisiert wurde – also /. Die Methode string() kann jedoch je nach Plattform unterschiedliche Werte zurückgeben. Unter Windows und Linux gibt diese Methode als Ergebnis / zurück. Das Ergebnis ist für diese beiden Plattformen identisch, weil auch Windows den Schrägstrich als Trennzeichen für Verzeichnisse akzeptiert, auch wenn der Backslash das bevorzugte Trennzeichen ist.

boost::filesystem::path bietet mehrere Methoden an, um auf bestimmte Teile eines Pfads zuzugreifen.

Beispiel 35.5. Zugriff auf Teilausdrücke in Pfadangaben
#include <boost/filesystem.hpp>
#include <iostream>

using namespace boost::filesystem;

int main()
{
  path p{"C:\\Windows\\System"};
  std::cout << p.root_name() << '\n';
  std::cout << p.root_directory() << '\n';
  std::cout << p.root_path() << '\n';
  std::cout << p.relative_path() << '\n';
  std::cout << p.parent_path() << '\n';
  std::cout << p.filename() << '\n';
}

Wenn Beispiel 35.5 unter Windows ausgeführt wird, wird der String C:\\Windows\\System als plattformabhängige Pfadangabe interpretiert. Daraufhin gibt root_name() "C:" zurück, root_directory() "\", root_path() "C:\", relative_path() "Windows\System", parent_path() "C:\Windows" und filename() "System".

Die im Beispiel aufgerufenen Methoden geben plattformabhängige Pfadangaben zurück. boost::filesystem::path speichert Pfadangaben intern im plattformabhängigen Format. Möchten Sie Pfadangaben im portablen Format erhalten, müssen Sie explizit Methoden wie generic_string() aufrufen.

Wenn Sie Beispiel 35.5 unter Linux ausführen, erhalten Sie andere Werte. So geben fast alle Methoden eine leere Zeichenkette zurück. Einzige Ausnahme sind relative_path() und filename(), die jeweils "C:\Windows\System" zurückgeben. Die Angabe C:\\Windows\\System wird demnach unter Linux als ein Dateiname interpretiert. Das ist insofern verständlich als dass es sich hierbei weder um eine portable Kodierung einer Pfadangabe noch um eine von Linux unterstützte plattformabhängige Kodierung handelt. Boost.Filesystem bleibt unter Linux nichts anderes übrig als die gesamte Angabe als Dateinamen zu interpretieren.

Boost.Filesystem bietet zusätzlich Methoden an, mit denen sich ermitteln lässt, ob das betreffende Teilstück in einem Pfad existiert. Diese Methoden lauten has_root_name(), has_root_directory(), has_root_path(), has_relative_path(), has_parent_path() und has_filename(). Sie alle haben einen Rückgabewert vom Typ bool.

Es gibt zwei weitere Methoden, mit denen ein Dateiname in seine Bestandteile zerlegt wird. Diese Methoden sollten nur dann aufgerufen werden, wenn has_filename() true zurückgibt. Ansonsten werden leere Strings zurückgegeben – wo kein Dateiname, kann nichts zerlegt werden.

Beispiel 35.6. Dateinamen und -endung erhalten
#include <boost/filesystem.hpp>
#include <iostream>

using namespace boost::filesystem;

int main()
{
  path p{"photo.jpg"};
  std::cout << p.stem() << '\n';
  std::cout << p.extension() << '\n';
}

Beispiel 35.6 gibt für stem() "photo" und für extension() ".jpg" zurück.

Es ist auch möglich, über Bestandteile eines Pfads zu iterieren.

Beispiel 35.7. Über Bestandteile eines Pfads iterieren
#include <boost/filesystem.hpp>
#include <iostream>

using namespace boost::filesystem;

int main()
{
  path p{"C:\\Windows\\System"};
  for (const path &pp : p)
    std::cout << pp << '\n';
}

Beispiel 35.7 gibt nacheinander "C:", "/", "Windows" und "System" aus – wenn das Programm unter Windows ausgeführt wird. Auf einem anderen Betriebssystem wie Linux lautet die Ausgabe "C:\Windows\System".

Nachdem Sie mehrere Methoden kennengelernt haben, um auf verschiedene Bestandteile eines Pfads zuzugreifen, lernen Sie im Beispiel 35.8 eine Methode kennen, mit der eine Pfadangabe geändert werden kann.

Beispiel 35.8. Pfadangaben mit operator/= aneinanderhängen
#include <boost/filesystem.hpp>
#include <iostream>

using namespace boost::filesystem;

int main()
{
  path p{"C:\\"};
  p /= "Windows\\System";
  std::cout << p.string() << '\n';
}

Im Beispiel 35.8 wird mit Hilfe des überladenen Operators operator/= ein Pfad an einen anderen gehängt. Das Beispiel gibt daher C:\Windows\System aus – unter Windows. Unter Linux wird C:\/Windows\System ausgegeben, da unter Linux der Schrägstrich das Trennzeichen für Dateien und Verzeichnisse ist. Dieser Schrägstrich ist auch der Grund, warum der Operator operator/= überladen wurde.

Neben operator/= bietet Boost.Filesystem zum Ändern einer Pfadangabe lediglich die Methoden remove_filename(), replace_extension() und make_preferred() an. Letztgenannte Methode ist speziell für den Einsatz unter Windows gedacht.

Beispiel 35.9. Bevorzugte Pfadangaben mit make_preferred()
#include <boost/filesystem.hpp>
#include <iostream>

using namespace boost::filesystem;

int main()
{
  path p{"C:/Windows/System"};
  std::cout << p.make_preferred() << '\n';
}

Auch wenn Pfadangaben unter Windows normalerweise den Backslash als Trennzeichen verwenden, akzeptiert Windows den Schrägstrich. So ist C:/Windows/System eine gültige native Pfadangabe unter Windows. Mit make_preferred() kann die Pfadangabe in die bevorzugte Schreibweise umgewandelt werden. So gibt Beispiel 35.9 "C:\Windows\System" aus.

Unter Linux und anderen POSIX-Plattformen ändert make_preferred() eine Pfadangabe nicht.

Beachten Sie, dass make_preferred() nicht nur die geänderte Pfadangabe zurückgibt, sondern auch das Objekt ändert, für das die Methode aufgerufen wird. Die nach dem Methodenaufruf intern in p gespeicherte Pfadangabe ist C:\Windows\System.