Série: C++
cpp
255 lignes
· Mis à jour 2026-04-03
filesystem.cpp
C++/Part4_現代CPP/Ch20_CPP17特性精選/filesystem.cpp
// Ch20 範例:std::filesystem(C++17 檔案系統)
// 編譯:g++ -std=c++17 -Wall -o filesystem filesystem.cpp
// 注意:某些舊版編譯器可能需要加上 -lstdc++fs
#include <iostream>
#include <string>
#include <fstream>
#include <filesystem>
#include <vector>
#include <iomanip>
#include <sstream>
namespace fs = std::filesystem;
// ============================================================
// 輔助函式
// ============================================================
void printSeparator(const std::string& title) {
std::cout << "\n" << std::string(60, '=') << "\n";
std::cout << title << "\n";
std::cout << std::string(60, '=') << "\n";
}
// 將位元組數轉為可讀的大小格式
std::string humanReadableSize(uintmax_t bytes) {
const char* units[] = {"B", "KB", "MB", "GB", "TB"};
int unitIdx = 0;
double size = static_cast<double>(bytes);
while (size >= 1024.0 && unitIdx < 4) {
size /= 1024.0;
++unitIdx;
}
std::ostringstream oss;
oss << std::fixed << std::setprecision(1) << size << " " << units[unitIdx];
return oss.str();
}
// 取得檔案類型的文字描述
std::string fileTypeString(const fs::directory_entry& entry) {
if (entry.is_regular_file()) return "[檔案]";
if (entry.is_directory()) return "[目錄]";
if (entry.is_symlink()) return "[符號連結]";
if (entry.is_block_file()) return "[區塊裝置]";
if (entry.is_character_file()) return "[字元裝置]";
if (entry.is_fifo()) return "[FIFO]";
if (entry.is_socket()) return "[Socket]";
return "[其他]";
}
// ============================================================
// 主程式
// ============================================================
int main() {
std::cout << std::string(60, '=') << "\n";
std::cout << "C++17 std::filesystem 檔案系統操作範例\n";
std::cout << std::string(60, '=') << "\n";
// --- 1. 路徑(fs::path)操作 ---
printSeparator("1. fs::path 路徑操作");
fs::path p1 = "/home/user/documents/report.txt";
std::cout << "完整路徑: " << p1 << "\n";
std::cout << "根路徑: " << p1.root_path() << "\n";
std::cout << "父目錄: " << p1.parent_path() << "\n";
std::cout << "檔案名稱: " << p1.filename() << "\n";
std::cout << "主檔名(stem):" << p1.stem() << "\n";
std::cout << "副檔名: " << p1.extension() << "\n";
// 路徑拼接
fs::path base = "/home/user";
fs::path file = "data.csv";
fs::path combined = base / "projects" / file; // 使用 / 運算子
std::cout << "\n路徑拼接:" << combined << "\n";
// 路徑比較與操作
fs::path p2 = "/home/user/../user/./documents/report.txt";
std::cout << "\n原始路徑: " << p2 << "\n";
// lexically_normal 只做字串層級的正規化,不需要檔案存在
std::cout << "正規化路徑: " << p2.lexically_normal() << "\n";
// --- 2. 取得目前工作目錄 ---
printSeparator("2. 目前工作目錄與暫存目錄");
std::cout << "目前工作目錄:" << fs::current_path() << "\n";
std::cout << "暫存目錄: " << fs::temp_directory_path() << "\n";
// --- 3. 建立測試用目錄與檔案 ---
printSeparator("3. 建立目錄與檔案");
// 建立測試目錄結構
fs::path testDir = fs::temp_directory_path() / "cpp17_fs_demo";
// 清理舊測試資料
if (fs::exists(testDir)) {
fs::remove_all(testDir);
}
// 建立目錄(含巢狀)
fs::create_directories(testDir / "subdir1" / "nested");
fs::create_directory(testDir / "subdir2");
std::cout << "已建立目錄結構:" << testDir << "\n";
// 建立測試檔案
std::vector<std::pair<std::string, std::string>> testFiles = {
{"hello.txt", "Hello, C++17 filesystem!"},
{"data.csv", "name,age,score\nAlice,20,95\nBob,21,87"},
{"notes.md", "# 筆記\n\n這是一個測試檔案。"},
{"subdir1/config.ini", "[settings]\nlang=zh-TW\ntheme=dark"},
{"subdir1/nested/deep.txt", "深層巢狀檔案"},
{"subdir2/log.txt", "2024-01-01 系統啟動\n2024-01-02 正常運作"},
};
for (const auto& [name, content] : testFiles) {
fs::path filePath = testDir / name;
std::ofstream ofs(filePath);
ofs << content;
ofs.close();
std::cout << " 已建立:" << name << "\n";
}
// --- 4. 檢查路徑是否存在與檔案類型 ---
printSeparator("4. 檢查檔案與目錄");
fs::path checkPath = testDir / "hello.txt";
std::cout << "路徑:" << checkPath << "\n";
std::cout << " exists: " << std::boolalpha << fs::exists(checkPath) << "\n";
std::cout << " is_regular_file:" << fs::is_regular_file(checkPath) << "\n";
std::cout << " is_directory: " << fs::is_directory(checkPath) << "\n";
std::cout << "\n路徑:" << testDir / "subdir1" << "\n";
std::cout << " exists: " << fs::exists(testDir / "subdir1") << "\n";
std::cout << " is_directory: " << fs::is_directory(testDir / "subdir1") << "\n";
std::cout << "\n路徑:" << testDir / "not_exist.txt" << "\n";
std::cout << " exists: " << fs::exists(testDir / "not_exist.txt") << "\n";
// --- 5. 檔案大小 ---
printSeparator("5. 檔案大小");
for (const auto& [name, content] : testFiles) {
fs::path filePath = testDir / name;
if (fs::is_regular_file(filePath)) {
auto size = fs::file_size(filePath);
std::cout << std::left << std::setw(30) << name
<< std::right << std::setw(8) << size << " bytes ("
<< humanReadableSize(size) << ")\n";
}
}
// --- 6. 目錄巡覽:directory_iterator ---
printSeparator("6. directory_iterator(只看第一層)");
std::cout << testDir << " 的內容:\n\n";
for (const auto& entry : fs::directory_iterator(testDir)) {
std::cout << " " << fileTypeString(entry) << " "
<< entry.path().filename();
if (entry.is_regular_file()) {
std::cout << " (" << humanReadableSize(entry.file_size()) << ")";
}
std::cout << "\n";
}
// --- 7. 遞迴目錄巡覽:recursive_directory_iterator ---
printSeparator("7. recursive_directory_iterator(遞迴巡覽)");
std::cout << testDir << " 的所有內容:\n\n";
for (const auto& entry : fs::recursive_directory_iterator(testDir)) {
// 計算相對於 testDir 的路徑來顯示層級
auto relPath = fs::relative(entry.path(), testDir);
int depth = 0;
for ([[maybe_unused]] const auto& part : relPath) ++depth;
std::cout << std::string(static_cast<size_t>((depth - 1) * 2), ' ')
<< fileTypeString(entry) << " "
<< entry.path().filename();
if (entry.is_regular_file()) {
std::cout << " (" << humanReadableSize(entry.file_size()) << ")";
}
std::cout << "\n";
}
// --- 8. 複製、改名、刪除 ---
printSeparator("8. 複製、改名、刪除操作");
// 複製檔案
fs::path src = testDir / "hello.txt";
fs::path dst = testDir / "hello_copy.txt";
fs::copy_file(src, dst, fs::copy_options::overwrite_existing);
std::cout << "已複製 hello.txt → hello_copy.txt\n";
std::cout << " 副本大小:" << fs::file_size(dst) << " bytes\n";
// 改名
fs::path renamed = testDir / "greeting.txt";
fs::rename(dst, renamed);
std::cout << "已改名 hello_copy.txt → greeting.txt\n";
std::cout << " hello_copy.txt 存在?" << std::boolalpha
<< fs::exists(dst) << "\n";
std::cout << " greeting.txt 存在?" << fs::exists(renamed) << "\n";
// 刪除單一檔案
fs::remove(renamed);
std::cout << "已刪除 greeting.txt\n";
// --- 9. 空間資訊 ---
printSeparator("9. 磁碟空間資訊");
auto spaceInfo = fs::space(testDir);
std::cout << "容量: " << humanReadableSize(spaceInfo.capacity) << "\n";
std::cout << "可用: " << humanReadableSize(spaceInfo.free) << "\n";
std::cout << "已用: " << humanReadableSize(spaceInfo.capacity - spaceInfo.free) << "\n";
// --- 10. 錯誤處理(使用 error_code 版本)---
printSeparator("10. 使用 error_code 處理錯誤");
std::error_code ec;
// 嘗試取得不存在檔案的大小
auto size = fs::file_size("/nonexistent/path/file.txt", ec);
if (ec) {
std::cout << "取得檔案大小失敗:" << ec.message() << "\n";
} else {
std::cout << "檔案大小:" << size << "\n";
}
// 嘗試建立已存在的目錄
bool created = fs::create_directory(testDir / "subdir1", ec);
std::cout << "建立已存在的目錄 → created = " << std::boolalpha << created;
if (ec) std::cout << ",錯誤:" << ec.message();
else std::cout << "(無錯誤,只是已存在)";
std::cout << "\n";
// --- 清理測試目錄 ---
printSeparator("清理");
auto removedCount = fs::remove_all(testDir);
std::cout << "已刪除 " << removedCount << " 個檔案/目錄\n";
std::cout << "測試目錄是否仍存在?" << std::boolalpha
<< fs::exists(testDir) << "\n";
// --- 總結 ---
printSeparator("總結");
std::cout << "std::filesystem 提供了跨平台的檔案系統操作:\n";
std::cout << " • fs::path — 路徑表示與操作\n";
std::cout << " • fs::exists / is_regular_file / is_directory — 檢查\n";
std::cout << " • fs::file_size — 取得檔案大小\n";
std::cout << " • fs::create_directory(ies) — 建立目錄\n";
std::cout << " • fs::copy_file / rename / remove — 檔案操作\n";
std::cout << " • fs::directory_iterator — 巡覽目錄\n";
std::cout << " • fs::recursive_directory_iterator — 遞迴巡覽\n";
std::cout << " • fs::space — 磁碟空間資訊\n";
std::cout << " • error_code 版本 — 不丟例外的錯誤處理\n";
return 0;
}
Articles liés
C++
c
Mis à jour 2026-07-21
deviceAlpha.h
deviceAlpha.h — c source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/deviceAlpha.h).
Lire l'article →
C++
c
Mis à jour 2026-07-21
finalproject.c
finalproject.c — c source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/finalproject.c).
Lire l'article →
C++
cpp
Mis à jour 2026-07-21
finalproject.cpp
finalproject.cpp — cpp source code from the C++ learning materials (C++/Mavis_Homework/FinalProject/finalproject.cpp).
Lire l'article →
C++
c
Mis à jour 2026-07-21
deviceAlpha.h
deviceAlpha.h — c source code from the C++ learning materials (C++/Mavis_Homework/Lab8/deviceAlpha.h).
Lire l'article →
C++
c
Mis à jour 2026-07-21
lab8.c
lab8.c — c source code from the C++ learning materials (C++/Mavis_Homework/Lab8/lab8.c).
Lire l'article →
C++
cpp
Mis à jour 2026-07-21
lab8.cpp
lab8.cpp — cpp source code from the C++ learning materials (C++/Mavis_Homework/Lab8/lab8.cpp).
Lire l'article →