Start Kontakt

std::filesystem w C++17 — zaawansowane zarządzanie plikami i katalogami

Wstęp

Standardowa biblioteka C++17 wprowadziła przestrzeń nazw std::filesystem, oferującą nowoczesny, przenośny i wygodny interfejs do pracy z systemem plików. To ogromne ułatwienie dla programistów, którzy wcześniej musieli korzystać z różnych bibliotek lub systemowych API, często specyficznych dla danej platformy.

W kontekście programowania gier, std::filesystem pozwala na łatwe zarządzanie zapisami, zasobami, konfiguracjami czy plikami tymczasowymi, co znacząco upraszcza kod i poprawia jego przenośność między systemami.

Podstawowe elementy std::filesystem

std::filesystem oferuje kilka kluczowych klas i funkcji, z którymi warto się zapoznać:

Tworzenie i sprawdzanie katalogów zapisów gry

W grach bardzo często wymagane jest tworzenie i kontrolowanie folderów, w których przechowujemy zapisy stanu gry. Dzięki std::filesystem możemy łatwo utworzyć folder, jeśli nie istnieje, oraz sprawdzić jego istnienie.

#include <iostream>
#include <filesystem>

namespace fs = std::filesystem;

int main() {
    fs::path save_dir = "savegame";

    if(!fs::exists(save_dir)) {
        std::cout << "Tworzenie katalogu zapisu..." << std::endl;
        if(fs::create_directory(save_dir)) {
            std::cout << "Katalog zapisów utworzony: " << save_dir << std::endl;
        } else {
            std::cout << "Nie udało się utworzyć katalogu zapisu!" << std::endl;
            return 1;
        }
    } else {
        std::cout << "Katalog zapisu istnieje: " << save_dir << std::endl;
    }
}

Przeglądanie zawartości katalogu — lista plików zapisów

Możemy również wypisać pliki w katalogu zapisów, co jest często potrzebne do wyświetlenia listy dostępnych stanów gry.

for(const auto & entry : fs::directory_iterator(save_dir)) {
    if(fs::is_regular_file(entry.status())) {
        std::cout << "Znaleziono plik: " << entry.path().filename() << std::endl;
    }
}

Sprawdzanie właściwości pliku i modyfikowanie ścieżek

std::filesystem pozwala łatwo manipulować ścieżkami, np. uzyskać nazwę pliku, rozszerzenie czy katalog nadrzędny.

fs::path file_path = "savegame/level1.sav";

std::cout << "Nazwa pliku: " << file_path.filename() << std::endl;
std::cout << "Rozszerzenie: " << file_path.extension() << std::endl;
std::cout << "Katalog nadrzędny: " << file_path.parent_path() << std::endl;

if(fs::exists(file_path)) {
    std::cout << "Rozmiar pliku: " << fs::file_size(file_path) << " bajtów" << std::endl;
}

Usuwanie plików i katalogów — czyszczenie zapisów

Gdy chcemy usunąć stare zapisy lub katalogi tymczasowe, std::filesystem oferuje łatwe metody usuwania pojedynczych plików lub całych drzew katalogów.

// Usunięcie pojedynczego pliku
fs::remove("savegame/old_save.sav");

// Usunięcie całego katalogu wraz z zawartością
fs::remove_all("savegame/temp");

Zastosowanie w programowaniu gier

W praktyce gry często potrzebują:

Dzięki std::filesystem można napisać kod, który działa zarówno na Windows, Linux, jak i macOS, bez konieczności ręcznego dostosowywania ścieżek czy używania systemowych funkcji.

Obsługa błędów i wyjątki

Wiele funkcji std::filesystem rzuca wyjątki typu std::filesystem::filesystem_error w przypadku błędów, np. braku uprawnień czy nieistniejących ścieżek. Dobrą praktyką jest obsługa tych wyjątków lub używanie wersji funkcji przyjmujących obiekt std::error_code, który pozwala na sprawdzenie błędu bez wyjątków.

Podsumowanie

std::filesystem to nowoczesna, przenośna i wygodna biblioteka do zarządzania plikami i katalogami w C++. Szczególnie przydatna w programowaniu gier, gdzie przenośność i efektywne zarządzanie zasobami i zapisami są bardzo ważne.

Warto ją znać i stosować, aby pisać czytelny, bezpieczny i łatwy w utrzymaniu kod obsługujący system plików niezależnie od platformy.