[譯]C++17,標準庫變化的更多細節
看到一個介紹 C++17 的系列博文(原文),有十來篇的樣子,覺得挺好,看看有時間能不能都簡單翻譯一下,這是第四篇~
之前的文章中我簡單介紹了一些C++17標準庫的新變化,這次我會介紹更多的相關細節.
讓我們首先來看下之前未提到過的新內容.
std::byte
獨立型別 std::byte 實現了 C++ 語言定義中的位元組概念,他能用於訪問物件的原始記憶體,不同於 char 等位元組型別(也可以用於訪問物件的原始記憶體), std::byte 只提供了位邏輯運算相關的介面方法.
namespace std { template <class IntType> constexpr byte operator<<(byte b, IntType shift); template <class IntType> constexpr byte operator>>(byte b, IntType shift); constexpr byte operator|(byte l, byte r); constexpr byte operator&(byte l, byte r); constexpr byte operator~(byte b); constexpr byte operator^(byte l, byte r); }
你可以使用 std::to_integer(std::byte b) 方法將 std::byte 轉化為整型或者使用 std::byte{integer} 將整型轉化為 std::byte,不過參與轉型的整數必須是一個小於 std::numeric_limits<unsigned_char>::max() 的非負數.
接著來看一些你應該已經知道的內容:
The filesystem library
我在之前的文章中介紹了C++17新引入的檔案系統庫.新的檔案系統庫基於3個概念: 檔案(file), 檔名(file name) 以及 檔案路徑(path). file 可以是目錄,硬連結,符號連結或者常規檔案.path 則可以是絕對路徑,規範路徑或者相對路徑(所謂規範路徑,是指不帶有符號連結, “.” 和 “…” 的檔案路徑).
你可以建立刪除目錄,遍歷目錄內容或者檢查檔案的各類屬性(示例程式碼如下).
#include <fstream> #include <iostream> #include <string> #include <filesystem> namespace fs = std::filesystem; int main() { std::cout << "Current path: " << fs::current_path() << std::endl; std::string dir = "sandbox/a/b"; fs::create_directories(dir); std::ofstream("sandbox/file1.txt"); fs::path symPath = fs::current_path() /= "sandbox"; symPath /= "syma"; fs::create_symlink("a", symPath); std::cout << "fs::is_directory(dir): " << fs::is_directory(dir) << std::endl; std::cout << "fs::exists(symPath): " << fs::exists(symPath) << std::endl; std::cout << "fs::symlink(symPath): " << fs::is_symlink(symPath) << std::endl; for (auto& p : fs::recursive_directory_iterator("sandbox")) { std::cout << p.path() << std::endl; } fs::remove_all("sandbox"); return 0; }
檔案系統庫還有更多的功能,這次我會介紹一些(至少對我來說)沒那麼明顯的特性,內容包括:
- 如何操作檔案許可權
- 如何讀取檔案修改時間
- 如何獲取檔案系統的空間大小
讓我們首先來看看如何操作檔案許可權.
Permissions
std::filesystem::perms 型別用以表示檔案許可權,他是一個位掩碼型別(BitmaskType),所以可以對其進行位運算操作.檔案的訪問許可權基於的是POSIX標準.
以下的示例來自於cppreference.com, 程式碼展示瞭如何讀取和操作 owner(擁有者), group(使用者組) 及 other(其他使用者)相關的檔案許可權.
#include <fstream>
#include <bitset>
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
void printPerms(fs::perms perm)
{
std::cout << ((perm & fs::perms::owner_read) != fs::perms::none ? "r" : "-")
<< ((perm & fs::perms::owner_write) != fs::perms::none ? "w" : "-")
<< ((perm & fs::perms::owner_exec) != fs::perms::none ? "x" : "-")
<< ((perm & fs::perms::group_read) != fs::perms::none ? "r" : "-")
<< ((perm & fs::perms::group_write) != fs::perms::none ? "w" : "-")
<< ((perm & fs::perms::group_exec) != fs::perms::none ? "x" : "-")
<< ((perm & fs::perms::others_read) != fs::perms::none ? "r" : "-")
<< ((perm & fs::perms::others_write) != fs::perms::none ? "w" : "-")
<< ((perm & fs::perms::others_exec) != fs::perms::none ? "x" : "-")
<< std::endl;
}
int main()
{
std::ofstream("rainer.txt");
std::cout << "Initial file permissions for a file: ";
printPerms(fs::status("rainer.txt").permissions());
fs::permissions("rainer.txt", fs::perms::owner_all | fs::perms::group_all, fs::perm_options::add);
std::cout << "Adding all bits to owner and group: ";
printPerms(fs::status("rainer.txt").permissions());
fs::permissions("rainer.txt", fs::perms::owner_write | fs::perms::group_write | fs::perms::others_write, fs::perm_options::remove);
std::cout << "Removing the write bits for all: ";
printPerms(fs::status("rainer.txt").permissions());
fs::remove("rainer.txt");
return 0;
}
程式碼24行中我建立了一個檔案(rainer.txt),通過使用全域性函式 std::filesystem::status::permissions, 我獲取了檔案的許可權資訊並使用 printPerms(第8行至20行) 函式來顯示他們.第29行中我使用 fs::perm_options::add 為檔案添加了 owner 和 group 的所有相關許可權,同樣在33行,我使用
fs::perm_options::remove 移除了owner, group 和 others 的檔案修改許可權,也就是說,我們可以移除一個檔案所有的修改許可權.
程式的輸出如下:
除了許可權,檔案還有修改時間的概念.
Time values
通過全域性函式 std::filesystem::last_write_time, 我們可以讀取和寫入一個檔案的最後修改時間.
#include <iostream>
#include <chrono>
#include <fstream>
#include <filesystem>
namespace fs = std::filesystem;
using namespace std::chrono_literals;
int main()
{
fs::path path = fs::current_path() / "rainer.txt";
std::ofstream(path.c_str());
auto ftime = fs::last_write_time(path);
std::time_t cftime = std::chrono::system_clock::to_time_t(ftime);
std::cout << "Write time on server " << std::asctime(std::localtime(&cftime));
std::cout << "Write time on server " << std::asctime(std::gmtime(&cftime)) << std::endl;
fs::last_write_time(path, ftime + 2h);
ftime = fs::last_write_time(path);
cftime = std::chrono::system_clock::to_time_t(ftime);
std::cout << "Local time on client " << std::asctime(std::localtime(&cftime)) << std::endl;
fs::remove(path);
return 0;
}
程式碼第13行我讀取了新建立檔案(rainer.txt)的修改時間(ftime),並使用該時間初始化了第15行的 std::chrono::system_clock. ftime 的型別為 std::filesystem::file_time_type, 在伺服器上(譯註:作者在cppreference.com網站上執行示例程式碼,所以有伺服器一說)似乎是 std::chrono::system_clock 型別的別名(譯註:就目前而言,MSVC中並非如此,std::filesystem::file_time_type 和 std::chrono::system_clock 是單獨的型別).第16行我使用轉換後的檔案修改時間初始化了 std::localtime 並文字化輸出了該日曆時間.如果我改用 std::gmtime(第17行),程式輸出卻並沒有什麼變化,這一度困擾了我,因為協調世界時(Coordinated Universal Time (UTC))在德國(譯註:作者為德國人)與本地時間應該有2個小時的時差,但是後來想到程式碼是在伺服器上執行的,而伺服器上的協調世界時與本地時間沒有時差,所以程式的輸出也就沒有變化了.
程式的輸出如下,程式碼第19行我手動為檔案的最後修改時間增加了2個小時,由此便得到了德國的本地時間(檔案的最後修改時間).
現在介紹一下新的檔案系統庫中最讓我吃驚的特性.
Space info
全域性函式 std::filesystem::space 可以返回一個 std::filesystem::space_info 物件,該物件包含了3個成員:
capacity, free 和 available.
- capacity: 檔案系統的總空間大小
- free: 檔案系統的空閒空間大小
- available: 可用於非特權程序的空閒空間大小(<= free)
這3個數據都是以位元組為單位,下面的示例程式碼中展示了基本用法(程式碼中的檔案路徑都在同一檔案系統下,所以相關的空間大小也是相同的).
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
fs::space_info root = fs::space("/");
fs::space_info usr = fs::space("/usr");
std::cout << ". Capacity Free Available\n"
<< "/ " << root.capacity << " "
<< root.free << " " << root.available << "\n"
<< "usr " << usr.capacity << " "
<< usr.free << " " << usr.available;
return 0;
}
程式的輸出如下: