C++Guns – RoboBlog

09.06.2019

C++ Guns: std::filesystem und std::regex

Filed under: Allgemein — Tags: — Thomas @ 07:06

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.

No Comments

No comments yet.

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.

Powered by WordPress