C++17中头文件filesystem的使用

      C++17引入了std::filesystem库(文件系统库, filesystem library),相关类及函数的声明在头文件filesystem中,命名空间为std::filesystem。

      1.path类:文件路径相关操作,如指定的路径是否存在等,其介绍参见:https://blog.csdn.net/fengbingchun/article/details/133217504
      2.directory_entry类:获取文件属性等,如指定文件是否是常规文件,还包括文件大小、文件最后修改时间,其介绍参见:https://blog.csdn.net/fengbingchun/article/details/133430293
      3.directory_iterator类:遍历目录,获取目录文件,不包括子目录,其介绍参见:https://blog.csdn.net/fengbingchun/article/details/133437356
      4.recursive_directory_iterator类:遍历目录,获取目录文件,包括子目录,其介绍参见:https://blog.csdn.net/fengbingchun/article/details/133437356
      5.filesystem_error类:异常类,继承自std::system_error,继承关系如下图所示:

      (1).path1, path2:返回存储在异常对象中的path;
      (2).what: 返回解释性字符串;
      (3).code: 返回错误码。

      测试代码如下所示:

int test_filesystem_filesystem_error()
{
	// path1, path2, whtat
	// creates a unique filename that does not name a currently existing file
	const fs::path oldp{ std::tmpnam(nullptr) }, newp{ std::tmpnam(nullptr) };

	/* windows:
		what():  rename: 系统找不到指定的文件。: "C:\Users\f06190\AppData\Local\Temp\sf2w.0", "C:\Users\f06190\AppData\Local\Temp\sf2w.1"
		path1(): "C:\\Users\\f06190\\AppData\\Local\\Temp\\sf2w.0"
		path2(): "C:\\Users\\f06190\\AppData\\Local\\Temp\\sf2w.1" */
	/* linux
		what():  filesystem error: cannot rename: No such file or directory [/tmp/filezJrUkO] [/tmp/filey7tqKV]
		path1(): "/tmp/filezJrUkO"
		path2(): "/tmp/filey7tqKV" */
	try {
		fs::rename(oldp, newp); // throws since oldp does not exist
	} catch (fs::filesystem_error const& ex) {
		std::cout << "what():  " << ex.what() << '\n'
			<< "path1(): " << ex.path1() << '\n'
			<< "path2(): " << ex.path2() << '\n';
	}

	return 0;
}

      6.file_status类:获取或设置有关文件类型(type)和权限(permissions)的信息
      (1).type: 获取或设置文件类型信息;
      (2).permissions: 获取或设置文件权限信息。

      测试代码如下所示:

void demo_status(const fs::path& p, fs::file_status s)
{
	std::cout << p;
	switch (s.type()) {
	case fs::file_type::none:
		std::cout << " has `not-evaluated-yet` type";
		break;
	case fs::file_type::not_found:
		std::cout << " does not exist";
		break;
	case fs::file_type::regular:
		std::cout << " is a regular file";
		break;
	case fs::file_type::directory:
		std::cout << " is a directory";
		break;
	case fs::file_type::symlink:
		std::cout << " is a symlink";
		break;
	case fs::file_type::block:
		std::cout << " is a block device";
		break;
	case fs::file_type::character:
		std::cout << " is a character device";
		break;
	case fs::file_type::fifo:
		std::cout << " is a named IPC pipe";
		break;
	case fs::file_type::socket:
		std::cout << " is a named IPC socket";
		break;
	case fs::file_type::unknown:
		std::cout << " has `unknown` type";
		break;
	default:
		std::cout << " has `implementation-defined` type";
		break;
	}
	std::cout << '\n';
}

void demo_perms(fs::perms p)
{
	using fs::perms;
	auto show = [=](char op, perms perm) {
		std::cout << (perms::none == (perm & p) ? '-' : op);
	};

	show('r', perms::owner_read);
	show('w', perms::owner_write);
	show('x', perms::owner_exec);
	show('r', perms::group_read);
	show('w', perms::group_write);
	show('x', perms::group_exec);
	show('r', perms::others_read);
	show('w', perms::others_write);
	show('x', perms::others_exec);
	std::cout << '\n';
}

int test_filesystem_file_status()
{
#ifdef _MSC_VER
	const std::string path{ "../../../testdata/list.txt" };
#else
	const std::string path{ "../../testdata/list.txt" };
#endif

	// 1. type
	// windows: "../../../testdata/list.txt" is a regular file
	// linux: "../../testdata/list.txt" is a regular file
	demo_status(path, fs::status(path));

	// 2. permissions
	demo_perms(fs::status(path).permissions()); // rwxrwxrwx

	return 0;
}

      7.space_info结构体:获取有关文件系统上的空闲(free)和可用空间(available space)的信息

struct space_info {
    std::uintmax_t capacity; // 总大小,以字节为单位
    std::uintmax_t free; // 可用空间,以字节为单位
    std::uintmax_t available; // 非特权进程可用的可用空间(可能等于或小于可用空间)
};
float get_file_size(std::uintmax_t size, std::string& suffix)
{
	float s1 = size / 1024. / 1024 / 1024;
	float s2 = size / 1024. / 1024;
	float s3 = size / 1024.;

	if (s1 > 1) {
		suffix = " GB";
		return s1;
	}
	if (s2 > 1) {
		suffix = " MB";
		return s2;
	}
	if (s3 > 1) {
		suffix = " KB";
		return s3;
	}
	suffix = " Bytes";
	return size;
}

int test_filesystem_space_info()
{
	fs::space_info info = fs::space(fs::current_path());
	std::cout << "current path: " << fs::current_path() << "  ";
	// windows: current path: "E:\\GitCode\\Messy_Test\\prj\\x86_x64_vc12\\CppBaseTest"   size: 311.00 GB   size: 189.23 GB   size: 189.23 GB
	// linux: current path: "/home/spring/GitCode/Messy_Test/prj/linux_cmake_CppBaseTest"   size: 311.00 GB   size: 189.23 GB   size: 189.23 GB
	for (auto x : { info.capacity, info.free, info.available }) {
		std::string suffix;
		auto value = get_file_size(static_cast(x), suffix);
		std::cout << " size: " << std::fixed << std::setprecision(2) << value << suffix << "  ";
	}
	std::cout << std::endl;

	return 0;
}

      8.file_type枚举类:文件的类型

enum class file_type {
    none = /* unspecified */,
    not_found = /* unspecified */,
    regular = /* unspecified */,
    directory = /* unspecified */,
    symlink = /* unspecified */,
    block = /* unspecified */,
    character = /* unspecified */,
    fifo = /* unspecified */,
    socket = /* unspecified */,
    unknown = /* unspecified */,
    /* implementation-defined */
};

      9.perms枚举类:文件访问权限,如下图所示

C++17中头文件filesystem的使用_第1张图片

      10.perm_options枚举类:控制函数std::filesystem::permissions()行为的可用选项,如下图所示:

enum class perm_options {
    replace = /* unspecified */,
    add = /* unspecified */,
    remove = /* unspecified */,
    nofollow = /* unspecified */
};

      11.非成员函数:
      (1).absolute:返回绝对路径;
      (2).canonical, weakly_canonical: 将指定路径转换为规范绝对路径(canonical absolute path),指定的路径必须存在;
      (3).relative, proximate: 返回相对路径;
      (4).copy: 拷贝文件或目录,会生成新的文件或目录,from指定的文件或目录必须存在,to指定的文件或目录必须不存在;
      (5).copy_file: 拷贝文件,会生成新的文件,from指定的文件必须存在,to指定的文件必须不存在;若发生错误,则返回false;
      (6).copy_symlink:拷贝符号链接;
      (7).create_directory, create_directories: 创建新目录,使用create_directory时要求父目录必须已存在,即create_directory不支持多级创建,而create_directories没有这些限制;
      (8).create_hard_link:创建硬链接;
      (9).create_symlink, create_directory_symlink: 创建符号链接;
      (10).current_path: 获取当前工作目录
      (11).exists: 检查指定的文件或目录是否存在
      (12).equivalent: 检查两个路径是否是相同的;
      (13).file_size: 获取文件大小
      (14).hard_link_count: 获取指定路径硬链接数;
      (15).last_write_time: 获取或设置指定路径最后一次修改时间
      (16).permissions: 修改文件访问权限;
      (17).read_symlink: 获取符号链接的target;
      (18).remove, remove_all:删除文件或空目录;remove_all可递归地删除文件或目录及其所有内容并返回已删除的文件和目录的数量;
      (19).rename: 重命名文件或目录
      (20).resize_file: 更改常规文件大小;
      (21).space: 获取指定的路径的可用空间
      (22).status, symlink_status: 获取文件属性,如指定路径是否是常规文件、是否是目录等;
      (23).temp_directory_path: 返回适合临时文件的目录
      std::error_code类是与平台相关的错误码。std::filesystem中的所有函数都有一个对应非抛出异常的对等接口

      测试代码如下所示:

int test_filesystem_non_member_functions()
{
	const fs::path p1 = "../funset.cpp";
#ifdef _MSC_VER
	const fs::path p2{ "../../../testdata/list.txt" }, p3{ "../../../testdata/list_copy.txt" }, p4{ "E:\\yulong.mp4" }, p5{ "../../../testdata/list_new.txt" };
#else
	const fs::path p2{ "../../testdata/list.txt" }, p3{ "../../testdata/list_copy.txt" }, p4{ "./build/CppBaseTest" }, p5{"../../testdata/list_new.txt"};
#endif
	// windows: current path is "E:\\GitCode\\Messy_Test\\prj\\x86_x64_vc12\\CppBaseTest"
	// linux: current path is "/home/spring/GitCode/Messy_Test/prj/linux_cmake_CppBaseTest"
	std::cout << "current path is " << fs::current_path() << '\n';
	// 1. absolute
	// windows: absolute path for "../funset.cpp" is "E:\\GitCode\\Messy_Test\\prj\\x86_x64_vc12\\funset.cpp"
	// linux: absolute path for "../funset.cpp" is "/home/spring/GitCode/Messy_Test/prj/linux_cmake_CppBaseTest/../funset.cpp"
	std::cout << "absolute path for " << p1 << " is " << fs::absolute(p1) << '\n';

	// 2. canonical, weakly_canonical
	/* windows:
		canonical path: "E:\\GitCode\\Messy_Test\\testdata\\list.txt"
		weakly canonical path: "E:\\GitCode\\Messy_Test\\testdata\\list.txt" */
	/* linux:
		canonical path: "/home/spring/GitCode/Messy_Test/testdata/list.txt"
		weakly canonical path: "/home/spring/GitCode/Messy_Test/testdata/list.txt" */
	std::cout << "canonical path: " << fs::canonical(p2) << "\n";
	std::cout << "weakly canonical path: " << fs::weakly_canonical(p2) << "\n";

	// 3. relative, proximate
	std::cout << "relative path: " << fs::relative("/a/b/c", "/a/b")
		<< ", proximat path: " << fs::proximate("/a/b/c", "/a/b") << "\n";	// relative path: "c", proximat path: "c"

	// 4. copy, exists, remove
	if (fs::exists(p3))
		fs::remove(p3);
	fs::copy(p2, p3);

	// 5. copy_file
	if (fs::exists(p3))
		fs::remove(p3);
	fs::copy_file(p2, p3);

	// 6. create_directory, create_directories
	fs::create_directory("./a");
	fs::create_directories("./b/c/d");

	// 7. equivalent
	if (fs::equivalent(".", fs::current_path()))
		std::cout << "they are equal" << "\n";

	// 8. file_size
	std::string suffix;
	auto value = get_file_size(static_cast(fs::file_size(p4)), suffix);
	// windows: size: 1.35 GB; linux: size: 7.61 MB
	std::cout << "size: " << std::fixed << std::setprecision(2) << value << suffix << "\n";

	// 9. last_write_time
	// windows: last write time: 2023-08-19 22:42:56
	// linux: last write time: 2023-10-03 12:32:49
	std::cout << "last write time: " << to_time_t(last_write_time(p4)) << std::endl;

	// 10. permissions
	// windows: rwxrwxrwx r-xr-xr-x
	// linux:   rw-rw-r-- -w-r-----
	demo_perms(fs::status(p3).permissions());
#ifdef _MSC_VER
	fs::permissions(p3, fs::perms::none);
#else
	fs::permissions(p3, fs::perms::owner_write | fs::perms::group_read);
#endif
	demo_perms(fs::status(p3).permissions());

	// 11. rename
	if (fs::exists(p5))
		fs::remove(p5);
	fs::rename(p3, p5);

	// 12. resize_file
	// linux: size: 187.00 Bytes  size: 64.00 KB
	value = get_file_size(static_cast(fs::file_size(p5)), suffix);
	std::cout << "size: " << std::fixed << std::setprecision(2) << value << suffix << "\n";
#ifdef __linux__
	fs::resize_file(p5, 64 * 1024); // resize to 64 KB, windows crash
	value = get_file_size(static_cast(fs::file_size(p5)), suffix);
	std::cout << "size: " << std::fixed << std::setprecision(2) << value << suffix << "\n";
#endif

	// 13. temp_directory_path
	// windows: temp directory is: "C:\\Users\\f06190\\AppData\\Local\\Temp\\"
	// linux: temp directory is: "/tmp"
	std::cout << "temp directory is: " << fs::temp_directory_path() << "\n";

	// std::error_code
	std::error_code ec;
	fs::copy_file("xxx", "yyy", ec); // does not throw
	// windows: error code: 2,系统找不到指定的文件。
	// linux: error code: 2,No such file or directory
	std::cout << "error code: " << ec.value() << "," << ec.message() << "\n";

	try {
		fs::copy_file("xxx", "yyy");
	} catch (fs::filesystem_error const& ex) {
		std::cout << "what():  " << ex.what() << '\n'
			<< "path1(): " << ex.path1() << '\n'
			<< "path2(): " << ex.path2() << '\n'
			<< "code().value():    " << ex.code().value() << '\n'
			<< "code().message():  " << ex.code().message() << '\n'
			<< "code().category(): " << ex.code().category().name() << '\n';
	}

	return 0;
}

      执行结果如下图所示:

C++17中头文件filesystem的使用_第2张图片

      12.文件类型:
      (1).is_block_file: 检查给定的文件或路径是否是块设备;
      (2).is_character_file: 检查给定的文件或路径是否是字符设备;
      (3).is_directory: 检查给定的文件或路径是否是目录
      (4).is_empty: 检查给定的文件或路径是否是空文件或空目录
      (5).is_fifo: 检查给定的文件或路径是否是命名管道;
      (6).is_other: 检查给定的文件或路径是否是其它文件;
      (7).is_regular_file: 检查给定的文件或路径是否是常规文件
      (8).is_socket: 检查给定的文件或路径是否是套接字;
      (9).is_symlink: 检查给定的文件或路径是否是符号链接;
      (10).status_known: 检查给定的文件是否已知。

      测试代码如下所示:

void demo_status2(const fs::path& p, fs::file_status s)
{
	std::cout << p;
	// alternative: switch(s.type()) { case fs::file_type::regular: ...}
	if (fs::is_regular_file(s))
		std::cout << " is a regular file\n";
	if (fs::is_directory(s))
		std::cout << " is a directory\n";
	if (fs::is_block_file(s))
		std::cout << " is a block device\n";
	if (fs::is_character_file(s))
		std::cout << " is a character device\n";
	if (fs::is_fifo(s))
		std::cout << " is a named IPC pipe\n";
	if (fs::is_socket(s))
		std::cout << " is a named IPC socket\n";
	if (fs::is_symlink(s))
		std::cout << " is a symlink\n";
	if (!fs::exists(s))
		std::cout << " does not exist\n";
	//if (fs::is_empty(p))
	//	std::cout << " is empty\n";
	if (fs::is_other(s)) // equivalent to exists(s) && !is_regular_file(s) && !is_directory(s) && !is_symlink(s)
		std::cout << " is other file\n";
	//if (fs::status_known(s)) // equivalent to s.type() != file_type::none
	//	std::cout << " is status known\n";
}

int test_filesystem_file_types()
{
	demo_status2("/dev/null", fs::status("/dev/null"));
	demo_status2("/dev/sda", fs::status("/dev/sda"));
	demo_status2(fs::current_path(), fs::status(fs::current_path()));
	demo_status2("/xxx/yyy", fs::status("/xxx/yyy"));
	demo_status2("/usr/bin/g++", fs::status("usr/bin/g++"));
	demo_status2("../../../testdata/list.txt", fs::status("../../../testdata/list.txt"));
	demo_status2("../../testdata/list.txt", fs::status("../../testdata/list.txt"));
	demo_status2("/mnt", fs::status("/mnt"));

	return 0;
}

      GitHub:https://github.com/fengbingchun/Messy_Test

你可能感兴趣的:(filesystem)