Heute mache ich die ersten Versuche mit std::filesystem und std::regex. Der GCC 8.1 ist installiert. Die Doku liegt bereit. Es kann los gehen.
std::filesystem
Ich möchte bestimmte "Müll" Dateien im Projekt Verzeichnis auflisten und ihren Speicherplatzverbrauch summieren. Die Handhabung von std::filesystem ist wirklich erstaunlich einfach. Klar strukturiert. Es funktioniert. Etwas, dass böse Zungen von std::chrono ja nicht behaupten.
Eine Schleife über alle Dateien in einem Verzeichnis geht echt fix:
#include <filesystem> #include <iostream> namespace fs = std::filesystem; for(auto& p: fs::recursive_directory_iterator("/", fs::directory_options::skip_permission_denied)) { if(p.is_regular_file()) { std::cout << p.path().filename() << " " << p.file_size() << '\n'; } }
Bis GCC 8 muss das Projekt noch explizit mit -lstdc++fs, ab GCC 9 dann nicht mehr.
Achtung: Beim GCC 8.1 und Netzlaufwerke hab ich festgestellt, dass is_regular_file() falsche Werte zurück gibt. Im Vergleich zu fs::is_regular_file(fs::status(p)), was das selbe macht. Ob das im GCC 9.1 auch so ist, muss ich noch prüfen.
Die Fehlerbehandlung ist auch nett gelöst. Man hat diesmal die Auswahl zwischen Exception und Error Code. Viele Funktionen kann ein error_eode Objekt übergeben werden (als Referenz nicht als Pointer woohoo!).
std::error_code ec; for(auto& p: fs::recursive_directory_iterator("/", fs::directory_options::skip_permission_denied, ec)) { if(e) { std::cout << e.message();
Oder mit Exception.
try { if(fs::is_regular_file(fs::status(p))) { } catch(fs::filesystem_error& err) { std::cerr << err.what() << "\n"; }
Als keiner Bonus hier meine std::filesystem::file_type ostream Funktion
std::ostream& operator<<(std::ostream& s, const std::filesystem::file_type type) { using std::filesystem::file_type; switch (type) { case file_type::none: s << "none"; break; case file_type::not_found: s << "not_found"; break; case file_type::regular: s << "regular"; break; case file_type::directory: s << "directory"; break; case file_type::symlink: s << "symlink"; break; case file_type::block: s << "block"; break; case file_type::character: s << "character"; break; case file_type::fifo: s << "fifo"; break; case file_type::socket: s << "socket"; break; case file_type::unknown: s << "unknown"; break; } return s; }
std::regex
Regex ist auch garnicht sooo schwer, wenn man es mal kann. Ich möchte alle Dateien dieser Form finden: dbg_0000 dbg_0001 u.s.w. Das passende Regex Objekt sieht dann so aus:
const std::regex dbg_regex("dbg_[[:digit:]]+"); for(auto& p: fs::recursive_directory_iterator("/", fs::directory_options::skip_permission_denied)) { if(p.is_regular_file()) { if(std::regex_match(p.path().filename().c_str(), dbg_regex)) { // found } } }
Als Verbindung zwischen Dateiname und Regex dient C-String. Da es string_view hier (noch?) nicht gibt.