3

[译]C++17,标准库变化的更多细节

 3 years ago
source link: https://blog.csdn.net/tkokof1/article/details/82380753
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

[译]C++17,标准库变化的更多细节

tkokof1 2018-09-04 11:22:44 740
分类专栏: 随性 语言

看到一个介绍 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;
}

程序的输出如下:

图


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK