檔案系統巡覽

標頭 <filesystem> 會實作 C++ 檔案系統技術規格 ISO/IEC TS 18822:2015(最終草稿: ISO/IEC JTC 1/SC 22/WG 21 N4100 ),並具有類型和函式,可讓您撰寫與平臺無關的程式碼來流覽檔案系統。 因為它是跨平臺,所以它包含與 Windows 系統無關的 API。 例如, is_fifo(const path&) 一律會在 Windows 上傳 false 回 。

概觀

<filesystem>針對下列工作使用 API:

  • 反覆查看指定路徑下的檔案和目錄

  • 取得檔案的相關資訊,包括建立時間、大小、副檔名和根目錄

  • 撰寫、分解以及比較路徑

  • 建立、複製和刪除目錄

  • 複製和刪除檔案

如需使用標準程式庫之檔案 IO 的詳細資訊,請參閱 iostream 程式設計

路徑

建構和組成路徑

Windows (自從 XP 以來) 中的路徑會以 Unicode 原生儲存。 類別 path 會自動執行所有必要的字串轉換。 它接受寬字元陣列和窄字元陣列的引數,以及 std::string 格式為 UTF8 或 UTF16 的 和 std::wstring 型別。 path 類別也會自動正規化路徑分隔符號。 您可以使用單一正斜線做為建構函式引數中的目錄分隔符號。 此分隔符號可讓您使用相同的字串,將路徑儲存在 Windows 和 UNIX 環境中:

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.

若要串連兩個路徑,可以使用多載的 //= 運算子。這兩個運算子類似於 std::stringstd::wstring 上的 ++= 運算子。 如果您不這麼做,物件 path 會方便提供分隔符號。

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

檢查路徑

path 類別有數種方法可傳回路徑本身各個部分的相關資訊。 這項資訊與它可能參考之檔案系統實體的相關資訊不同。 您可以取得根、相對路徑、檔名、副檔名等等。 您可以反覆查看路徑物件,檢查階層中的所有資料夾。 下列範例示範如何逐一查看路徑物件。 以及如何擷取其元件的相關資訊。

// 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);
}

程式碼會產生以下輸出:

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

比較路徑

path 類別會多載與 std::stringstd::wstring相同的比較運算子。 當您比較兩個路徑時,您會在分隔符號正規化之後進行字串比較。 如果遺漏尾端斜線(或反斜線),則不會新增它,且會影響比較。 下列範例將示範如何比較路徑值:

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

若要執行此程式碼,請將其貼到完整範例上方的 main 之前,並取消註解 main 中呼叫程式碼的那一行。

在路徑和字串類型之間轉換

path 物件隱含可以轉換成 std::wstringstd::string的能力。 這表示您可以將路徑傳遞至 函式,例如 wofstream::open ,如下列範例所示:

// 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

逐一查看目錄和檔案

標頭 <filesystem> 會提供類型 directory_iterator 來逐一查看單一目錄,而 類別 recursive_directory_iterator 則以遞迴方式逐一查看目錄及其子目錄。 當您藉由傳遞 path 來建構迭代器之後,迭代器會指向路徑中的第一個 directory_entry。 透過呼叫預設建構函式來建立結尾迭代器。

逐一查看目錄時,您可能會發現數種專案。 這些專案包括目錄、檔案、符號連結、通訊端檔案和其他專案。 會 directory_iterator 以 物件的形式 directory_entry 傳回其專案。