namespace cpp

C++ lernen, kennen, anwenden

Benutzer-Werkzeuge

Webseiten-Werkzeuge


kennen:include:filesystem

<filesystem>

Diese Bibliothek erlaubt weitgehend systemunabhängigen Zugriff auf das Dateisystem. Für eine umfassende, detailliertere Beschreibung siehe <filesystem>. Hier folgen eher Anwendungsbeispiele.

Einbinden

Vor der Integration in C++17 wurde zunächst Filesystem TS veröffentlicht. Notfalls kann auf diese Version zurückgegriffen werden:

#if __has_include(<filesystem>)
  #include <filesystem>
  namespace fs = std::filesystem;
#elif __has_include(<experimental/filesystem>)
  #include <experimental/filesystem>
  namespace fs = std::experimental::filesystem;
  // g++ : link with -lstdc++fs
#else
  #error No filesystem library.
#endif

Pfade

Ein Pfad fs::path beschreibt den Weg zu einer Datei im Dateisystem absolut zur Wurzel oder relativ zu fs::current_path(). Er besteht aus

  • einem optionalen p.root_name() — unter Windows ein Laufwerk C: oder //server,
  • einem optionalen p.root_directory() – je nach Betriebsystem / oder \,
  • und weiteren Namen, die — bis auf den letzten — Namen von Verzeichnissen sein müssen.

Dabei sind Verzeichnisse ebenfalls Dateien, auch . und .. — aktuelles und übergeordnetes Verzeichnis. Als Pfadtrenner sind sowohl / als auch \ nutzbar. Der Dateiname p.filename() regulärer Dateien besteht oft aus zwei durch Punkt getrennten Teilen, p.stem() und p.extension().

      Wurzelverzeichnis
      v              Dateiname 
    E:/temp/a/simple/example.txt
    /  ~~~~~~~~~~~~~ ------- ~~~
    LW  Relativpfad   Stamm  Erweiterung

Über die Bestandteile eines Pfades kann iteriert werden.

  for (const auto& e : fs::path("E:/temp/a/simple/example.txt")) 
    std::cout << e << ' ';  

Die Ausgaben erscheinen als "quoted" strings:

  "E:" "/" "temp" "a" "simple" "example.txt"

Berechtigungen

Dateien und Verzeichnisse können nur von bestimmten Nutzern gelesen, geschrieben und ausgeführt werden. Diese Berechtigungen lassen sich in einer kurzen Zeichenkette zusammenfassen (hier ohne set_uid, set_gid und sticky_bit):

auto perm_string(fs::perms p)
{
  auto table = 
  { std::pair
    {fs::perms::owner_read,  "-r"},
    {fs::perms::owner_write, "-w"},
    {fs::perms::owner_exec,  "-x"},
    {fs::perms::group_read,  "-r"},
    {fs::perms::group_write, "-w"},
    {fs::perms::group_exec,  "-x"},
    {fs::perms::others_read, "-r"},
    {fs::perms::others_write,"-w"},
    {fs::perms::others_exec, "-x"},
  };
  auto sign = [p] (auto flag, const char s[]) { return s[(p & flag) != fs::perms::none]; };
  std::ostringstream os;
  for (auto&& [flag, s] : table) os << sign(flag, s);
  return os.str();		  
}

Dateieigenschaften abfragen

Für einen vorgegebenen Pfad lassen sich alle Eigenschaften anzeigen:

void show(fs::path path)
{
  if (!fs::exists(path))
  {
    std::cout << path << " file does not exist\n";
    return; 
  }
  auto perms = perm_string(fs::status(path).permissions());
  using clock = std::chrono::system_clock;
  auto time = clock::to_time_t(fs::last_write_time(path)); 
  auto timestr = std::string(std::asctime(std::localtime(&time)));
  timestr.pop_back(); // get rid of '\n';
  std::cout << (fs::is_directory(path)? "d" : " ") << perms << " " << timestr << " "
    << (fs::is_regular_file(path)? std::to_string(fs::file_size(path)) + " " : "")  
    << path << '\n';
}
 
void ls()
{
  auto p = fs::current_path();
  show(p);
  for (auto&& entry : fs::directory_iterator(p))
    show(entry);
}    

Mit einem fs::directory_iterator kann ein gesamtes Verzeichnis durchlaufen werden, mit fs::recursive_directory_iterator einschließlich Unterverzeichnisse. Ein Demoprogramm liefert die ein wenig an das Kommando ls erinnernde Ausgabe:

drwx------ Mon Feb  5 00:26:47 2018 "/home/jail"
 rw------- Mon Feb  5 00:26:45 2018 1395 "/home/jail/prog.cc"
 rwxr-xr-x Mon Feb  5 00:26:47 2018 2648576 "/home/jail/prog.exe"

Dateiarbeit

Verzeichnisse anlegen

void create()
{
  fs::create_directories("sandbox/a/b");
  std::ofstream("sandbox/file1.txt") << "Hello";
  std::ofstream("sandbox/a/file2.txt") << "World";
}

kopieren

void copy()
{
  fs::create_directories("sandbox/c");
  fs::rename("sandbox/a/file2.txt", "sandbox/a/file3.txt");
  fs::copy("sandbox/a/file3.txt", "sandbox/c/file3.txt");
  // TODO: fs::copy_directory("sandbox/a", "sandbox/d"); // erstellt nur Verzeichnis
}

löschen

void destroy()
{
  fs::remove("sandbox/file1.txt"); 
  fs::remove("sandbox/a/b"); 
  fs::remove_all("sandbox"); 	
}

Ausnahmen und Fehlerbehandlung

Im Fehlerfall können die Funktionen eine Ausnahme vom Typ fs::filesystem_error werfen. Zu allen Funktionen und Methoden exstieren Varianten, die Fehler über eine std::error_code-Referenz als zusätzlichen, letzten Parameter mitteilen.

kennen/include/filesystem.txt · Zuletzt geändert: 2018-05-13 18:17 von rrichter