C + + standard - C++17 features - file system - path processing

Posted by kidd1270 on Tue, 25 Jan 2022 12:00:47 +0100


type The object of path represents the path on the file system. Only the syntax appearance of the path is handled: The pathname may represent a path that does not exist, or even a path that is not allowed to exist on the current file system or operating system.

Path names have the following syntax:

  1. Root name (optional): identifies a file system with multiple root directories (such as "C:" or "/ / myserver"). In case of ambiguity, the longest sequence constituting the legal root name shall be regarded as the root name. The standard library can define additional root names in addition to the root names known by the OS API.
  2. Root directory (optional): Directory separator. If it exists, mark this path as absolute. If it is missing (and the first element different from the root name is the file name), the path is relative and another path is required as the starting position for solving this file name.
  3. Include 0 or more of the following syntax:
  • File name: a sequence of characters that does not consist of directory separators or preferred directory separators (operating system or file system may impose additional restrictions). This name may identify a file, hard link, or directory. There are two special file names that need to be recognized: (current directory) (upper level directory).
  • Directory separators: forward slash characters and / or as path:: preferred_ Another character provided by separator. If this character is repeated, it is processed as a single directory separator: / usr///lib is the same as / usr/lib.

You can standardize paths by:

  1. If the path is empty, stop (the normal form of empty path is empty path);
  2. Replace each directory separator (which can be composed of multiple slashes) with a single path::preferred_separator;
  3. Replace each slash character in the root directory name with path::preferred_separator;
  4. Remove each And the following directory separator;
  5. Remove each non And the following directory separator and;
  6. If there is a root directory, remove all immediately following And any directory separator;
  7. If the last file name is, Remove all directory separators at the end;
  8. If the directory is empty, you need to add a.

1, Decompose

#include <iostream>
#include <filesystem>
using namespace std;
using namespace std::filesystem;

int main()
{
	path p("E:/Project/c++/main.cpp");
	cout << "path root name is : " << p.root_name() << endl;
	cout << "path root directory is : " << p.root_directory() << endl;
	cout << "path root path is : " << p.root_path() << endl;
	cout << "path relative path is : " << p.relative_path() << endl;
	cout << "path parent path is : " << p.parent_path() << endl;
	cout << "path filename is : " << p.filename() << endl;
	cout << "path stem is : " << p.stem() << p.stem() << endl;
	cout << "path extension is : " << p.extension() << endl;
}


The string returned by stem is from the beginning of the file name to the last.

2, Inquiry

3, Splicing

1,append,/=


Take the first form as an example:

  • If p.is_ absolute() || (p.has_root_name() && p.root_ name() != root_ Name ()), then replace the current path with P, as with operator=(p) and terminate;
  • Otherwise, if p.has_root_directory(), then remove any root directory and the entire relative path of the generic format pathname of * this;
  • Otherwise, if has_ filename() || (!has_root_directory() && is_ Absolute()), then attach path:: preferred_ General format from separator to this;
  • After processing with one of the above, attach the native format pathname of p to the native format of this, and ignore any root name from the general format of p.

The output of directly splicing directories or file names for the root directory may look strange, but the operating environment can determine the corresponding files or directories:

int main()
{
	path newPath1 = path("E:Project") / "test.cpp";
	path newPath2 = path("E:") / "test.cpp";

	cout << "newPath1 = " << newPath1 << " newPath2 = " << newPath2 << endl;
	copy(newPath1, newPath2);
}


2,concat,+=

Compared with the previous, concat and + = do not insert directory separators anyway.

4, Modification

int main()
{
	path p("E:/Project/c++/main.cpp");
	path other("E:Project");
	cout << "original path : " << p << endl;
	cout << "preffered path : " << p.make_preferred() << endl;
	cout << "remove filename : " << p.remove_filename() << endl;
	cout << "replace filename : " << p.replace_filename("test") << endl;
	cout << "replace extension : " << p.replace_extension("cc") << endl;
	p.swap(other);
	cout << "after swap : " << p << endl;
	p.clear();
	cout << "after clear : " << p << endl;
}

5, Traversal

path supports the begin and end interfaces so that we can access them like containers:

int main()
{
	path dir("E:/Project/c++/");
	path file("E:/Project/c++/main.cpp");
	
	cout << "visit dir:" << endl;
	for (path sub : dir)
	{
		cout << sub << " ";
	}

	cout << endl << "visit path:" << endl;
	for (path sub : file)
	{
		cout << sub << " ";
	}
}

6, Compare

The path class supports path comparison through the compare method and various comparison operators.

The sorting method between path objects is:

  • If root_ name(). native(). compare(p.root_name(). If native() is non-zero, this value is returned (actually a string comparison).
  • Otherwise, if has_root_directory() != p.has_root_directory(), if has_ root_ If directory() is false, a value less than zero will be returned; otherwise, a value greater than zero will be returned.
  • Otherwise, the value less than, equal to or greater than 0 will be returned. If the relative_path () of path is less than, equal to or greater than the relative part of P (p.relative_path()) in dictionary order. Compare on an element by element basis, like iterating the path from begin() to end().
template<class T>
void compare(T lhs, T rhs) 
{
	auto result = lhs.compare(rhs);
	cout << lhs << " " << (result > 0 ? ">" : (result < 0 ? "<" : "==")) << " " << rhs << endl;
}

int main()
{
	path path1("E:/Project/c++/");
	path path2("E:/Project/");
	path path3("E:/Project/c++/main.cpp");
	path path4("D:/Project/c++");
	path path5("F:/Project/c++");
	path path6("Project/c++");
	
	compare(path1, path1);
	compare(path1, path2);
	compare(path1, path3);
	compare(path1, path4);
	compare(path1, path5);
	compare(path1, path6);
}

Topics: C++ Back-end Path