[译]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;
}

文件系统库还有更多的功能,这次我会介绍一些(至少对我来说)没那么明显的特性,内容包括:

  • 如何操作文件权限
  • 如何读取文件修改时间
  • 如何获取文件系统的空间大小

让我们首先来看看如何操作文件权限.

扫描二维码关注公众号,回复: 4191816 查看本文章

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

程序的输出如下:

图

猜你喜欢

转载自blog.csdn.net/tkokof1/article/details/82380753