Bestandssysteemnavigatie

De C++17-header <filesystem> biedt typen en functies waarmee u platformonafhankelijke code kunt schrijven voor het navigeren in het bestandssysteem. Omdat het platformoverschrijdend is, bevat het API's die niet relevant zijn voor Windows systemen. Retourneert false bijvoorbeeld is_fifo(const path&) altijd Windows.

Opmerking

In dit artikel wordt de huidige C++17-bibliotheek std::filesystem behandeld. Zie voor de historische vooraf gedefinieerde MSVC-implementatie die is verwijderd vanaf MSVC versie 14.51 <experimental/filesystem>.

Overview

Gebruik de <filesystem> API's voor de volgende taken:

  • herhalen over bestanden en mappen onder een opgegeven pad

  • informatie ophalen over bestanden, waaronder de tijd die is gemaakt, de grootte, de extensie en de hoofdmap

  • paden opstellen, opsponeren en vergelijken

  • mappen maken, kopiëren en verwijderen

  • bestanden kopiëren en verwijderen

Zie Iostream Programming voor meer informatie over File IO met behulp van de Standard-bibliotheek.

Paths

Paden maken en opstellen

Paden in Windows (sinds XP) worden systeemeigen opgeslagen in Unicode. De path klasse voert automatisch alle benodigde tekenreeksconversies uit. Het accepteert argumenten van zowel brede als smalle tekenmatrices, en zowel std::string als std::wstring typen die zijn opgemaakt als UTF8 of UTF16. De path klasse normaliseert ook automatisch padscheidingstekens. U kunt één slash gebruiken als een adreslijstscheidingsteken in constructorargumenten. Met dit scheidingsteken kunt u dezelfde tekenreeksen gebruiken om paden op te slaan in zowel Windows als UNIX-omgevingen:

path pathToDisplay(L"/FileSystemTest/SubDir3");     // OK!
path pathToDisplay2(L"\\FileSystemTest\\SubDir3");  // Still OK as always
path pathToDisplay3(LR"(\FileSystemTest\SubDir3)"); // Raw string literals are OK, too.

Als u twee paden wilt samenvoegen, kunt u de overbelaste / en /= operators gebruiken, die vergelijkbaar zijn met de + operatoren += op std::string en std::wstring. Het path object levert de scheidingstekens handig als u dat niet doet.

path myRoot("C:/FileSystemTest");  // no trailing separator, no problem!
myRoot /= path("SubDirRoot");      // C:/FileSystemTest/SubDirRoot

Paden onderzoeken

De padklasse heeft verschillende methoden die informatie retourneren over verschillende onderdelen van het pad zelf. Deze informatie verschilt van de informatie over de bestandssysteementiteit waarnaar deze mogelijk verwijst. U kunt de hoofdmap, het relatieve pad, de bestandsnaam, de bestandsextensie en meer ophalen. U kunt een padobject herhalen om alle mappen in de hiërarchie te onderzoeken. In het volgende voorbeeld ziet u hoe u een padobject kunt herhalen. En hoe u informatie over de onderdelen ophaalt.

// filesystem_path_example.cpp
// compile by using: /EHsc /W4 /permissive- /std:c++17 (or later)
#include <string>
#include <iostream>
#include <sstream>
#include <filesystem>

using namespace std;
using namespace std::filesystem;

wstring DisplayPathInfo()
{
    // This path may or may not refer to an existing file. We are
    // examining this path string, not file system objects.
    path pathToDisplay(L"C:/FileSystemTest/SubDir3/SubDirLevel2/File2.txt ");

    wostringstream wos;
    int i = 0;
    wos << L"Displaying path info for: " << pathToDisplay << endl;
    for (path::iterator itr = pathToDisplay.begin(); itr != pathToDisplay.end(); ++itr)
    {
        wos << L"path part: " << i++ << L" = " << *itr << endl;
    }

    wos << L"root_name() = " << pathToDisplay.root_name() << endl
        << L"root_path() = " << pathToDisplay.root_path() << endl
        << L"relative_path() = " << pathToDisplay.relative_path() << endl
        << L"parent_path() = " << pathToDisplay.parent_path() << endl
        << L"filename() = " << pathToDisplay.filename() << endl
        << L"stem() = " << pathToDisplay.stem() << endl
        << L"extension() = " << pathToDisplay.extension() << endl;

    return wos.str();
}

int main()
{
    wcout << DisplayPathInfo() << endl;
    // wcout << ComparePaths() << endl; // see following example
    wcout << endl << L"Press Enter to exit" << endl;
    wstring input;
    getline(wcin, input);
}

De code produceert deze uitvoer:

Displaying path info for: C:\FileSystemTest\SubDir3\SubDirLevel2\File2.txt
path part: 0 = C:
path part: 1 = \
path part: 2 = FileSystemTest
path part: 3 = SubDir3
path part: 4 = SubDirLevel2
path part: 5 = File2.txt
root_name() = C:
root_path() = C:\
relative_path() = FileSystemTest\SubDir3\SubDirLevel2\File2.txt
parent_path() = C:\FileSystemTest\SubDir3\SubDirLevel2
filename() = File2.txt
stem() = File2
extension() = .txt

Paden vergelijken

De path klasse overbelast dezelfde vergelijkingsoperatoren als std::string en std::wstring. Wanneer u twee paden vergelijkt, maakt u een tekenreeksvergelijking nadat de scheidingstekens zijn genormaliseerd. Als er een afsluitende slash (of backslash) ontbreekt, wordt deze niet toegevoegd en is dit van invloed op de vergelijking. In het volgende voorbeeld ziet u hoe padwaarden zich verhouden:

wstring ComparePaths()
{
    path p0(L"C:/Documents");                 // no trailing separator
    path p1(L"C:/Documents/");                // p0 < p1
    path p2(L"C:/Documents/2013/");           // p1 < p2
    path p3(L"C:/Documents/2013/Reports/");   // p2 < p3
    path p4(L"C:/Documents/2014/");           // p3 < p4
    path p5(L"D:/Documents/2013/Reports/");   // p4 < p5

    wostringstream wos;
    wos << boolalpha <<
        p0.wstring() << L" < " << p1.wstring() << L": " << (p0 < p1) << endl <<
        p1.wstring() << L" < " << p2.wstring() << L": " << (p1 < p2) << endl <<
        p2.wstring() << L" < " << p3.wstring() << L": " << (p2 < p3) << endl <<
        p3.wstring() << L" < " << p4.wstring() << L": " << (p3 < p4) << endl <<
        p4.wstring() << L" < " << p5.wstring() << L": " << (p4 < p5) << endl;
    return wos.str();
}
C:\Documents < C:\Documents\: true
C:\Documents\ < C:\Documents\2013\: true
C:\Documents\2013\ < C:\Documents\2013\Reports\: true
C:\Documents\2013\Reports\ < C:\Documents\2014\: true
C:\Documents\2014\ < D:\Documents\2013\Reports\: true

Als u deze code wilt uitvoeren, plakt u deze in het volledige voorbeeld hierboven voordat main u commentaar maakt op de regel die deze in het hoofd aanroept.

Converteren tussen pad- en tekenreekstypen

Een path object is impliciet converteerbaar naar std::wstring of std::string. Dit betekent dat u een pad naar functies kunt doorgeven, zoals wofstream::openwordt weergegeven in dit voorbeeld:

// filesystem_path_conversion.cpp
// compile by using: /EHsc /W4 /permissive- /std:c++17 (or later)
#include <string>
#include <iostream>
#include <fstream>
#include <filesystem>

using namespace std;
using namespace std::filesystem;

int main()
{
    const wchar_t* p{ L"C:/Users/Public/Documents" };
    path filePath(p);

    filePath /= L"NewFile.txt";

    // Open, write to, and close the file.
    wofstream writeFile(filePath, ios::out);  // implicit conversion
    writeFile << L"Lorem ipsum\nDolor sit amet";
    writeFile.close();

    // Open, read, and close the file.
    wifstream readFile;
    wstring line;
    readFile.open(filePath);  // implicit conversions
    wcout << L"File " << filePath << L" contains:" << endl;
    while (readFile.good())
    {
        getline(readFile, line);
        wcout << line << endl;
    }
    readFile.close();

    wcout << endl << L"Press Enter to exit" << endl;
    wstring input;
    getline(wcin, input);
}
File C:\Users\Public\Documents\NewFile.txt contains:
Lorem ipsum
Dolor sit amet

Press Enter to exit

Mappen en bestanden herhalen

De <filesystem> header biedt het directory_iterator type voor het herhalen van één directory en de recursive_directory_iterator klasse voor het recursief herhalen van een map en de bijbehorende submappen. Nadat u een iterator hebt gemaakt door een path object door te geven, wijst de iterator naar de eerste directory_entry in het pad. Maak de end-iterator door de standaardconstructor aan te roepen.

Wanneer u door een map bladert, zijn er verschillende soorten items die u kunt detecteren. Deze items omvatten mappen, bestanden, symbolische koppelingen, socketbestanden en andere. De directory_iterator items worden geretourneerd als directory_entry objecten.