C++与python文件系统对比
目录
C++17 和 python 中好用的文件操作 | filesystem | os | shutil
C++ 17 | python | 功能 |
---|---|---|
filesystem::path::is_absolute() |
os.path.isabs() |
判断是否为绝对路径 |
filesystem::path::parent_path() |
os.path.dirname() |
路径分割 |
filesystem::path::filename() |
os.path.basename() |
路径分割 |
filesystem::operator/() |
os.path.join() |
路径拼接 |
filesystem::current_path() |
os.getcwd() |
获取当前路径 |
filesystem::directory_iterator |
os.listdir() |
返回指定目录下的所有文件/文件夹 |
filesystem::recursive_directory_iterator |
os.walk() |
递归返回指定目录下的所有文件/文件夹 |
filesystem::exists() |
os.path.exists() |
判断路径是否存在 |
filesystem::is_regular_file() |
os.path.isfile() |
判断路径是文件还是目录 |
filesystem::is_directory() |
os.path.isdir() |
判断路径是文件还是目录 |
filesystem::absolute() |
os.path.abspath() |
返回绝对路径 |
filesystem::copy_file() |
shutil.copyfile() |
文件拷贝 |
filesystem::remove() |
os.remove() |
文件删除 |
filesystem::copy() |
shutil.copytree |
路径拷贝 |
filesystem::remove_all |
shutil.rmtree() |
路径删除 |
filesystem::path
vs. os.path
filesystem::path
是一个类,里面封装了很多方法,我们通过实例化之后直接调用方法。os.path
是一个模块,里面有很多函数,可以直接调用。
判断是否为绝对路径
什么是绝对路径?我个人的理解是从根目录开始的就是绝对路径,例如/usr/local
和C:\\Users
,其余都是相对路径。可以发现,在不同操作系统中路径的分割符是不同的。同时在相对路径中./
和../
有特殊含义,./
表示当前目录,../
表示上一层目录,相应地,../../
就是上两层目录。
1.filesystem::path
中提供了判断是否为绝对路径/相对路径方法。
_LIBCPP_INLINE_VISIBILITY bool is_absolute() const {
return has_root_directory();
}
_LIBCPP_INLINE_VISIBILITY bool is_relative() const { return !is_absolute(); }
可以发现,判断相对路径的结果就是绝对路径取反。
void eg1_1() {
/*判断是否为绝对路径*/
// std::filesystem::path abs_path = "C:\\Users";
std::filesystem::path abs_path = "/usr/local"; // 注意,实例化path的时候可以直接用等号
std::cout << "abs_path.is_absolute() : " << abs_path.is_absolute() << std::endl;
std::cout << "abs_path.is_relative() : " << abs_path.is_relative() << std::endl;
std::filesystem::path rel_path = "../";
std::cout << "rel_path.is_absolute() : " << rel_path.is_absolute() << std::endl;
std::cout << "rel_path.is_relative() : " << rel_path.is_relative() << std::endl;
}
abs_path.is_absolute() : 1
abs_path.is_relative() : 0
rel_path.is_absolute() : 0
rel_path.is_relative() : 1
os.path
中提供了isabs()
函数用于判断是否为绝对路径。
def eg1_1():
"""判断是否为绝对路径"""
# abs_path = "C:\\Users"
abs_path = "/usr/local"
print("os.path.isabs({}) : {}".format(abs_path, os.path.isabs(abs_path)))
rel_path = "../"
print("os.path.isabs({}) : {}".format(rel_path, os.path.isabs(rel_path)))
os.path.isabs(/usr/local) : True
os.path.isabs(../) : False
路径分割
filesystem::path
中提供了路径分割的方法。
// decomposition
_LIBCPP_INLINE_VISIBILITY path root_name() const {
return string_type(__root_name());
}
_LIBCPP_INLINE_VISIBILITY path root_directory() const {
return string_type(__root_directory());
}
_LIBCPP_INLINE_VISIBILITY path root_path() const {
return root_name().append(string_type(__root_directory()));
}
_LIBCPP_INLINE_VISIBILITY path relative_path() const {
return string_type(__relative_path());
}
_LIBCPP_INLINE_VISIBILITY path parent_path() const {
return string_type(__parent_path());
}
_LIBCPP_INLINE_VISIBILITY path filename() const {
return string_type(__filename());
}
_LIBCPP_INLINE_VISIBILITY path stem() const { return string_type(__stem()); }
_LIBCPP_INLINE_VISIBILITY path extension() const {
return string_type(__extension());
}
void eg1_2() {
/*路径分割*/
std::filesystem::path path = "../test_dir/1.txt";
std::cout << "path.relative_path() : " << path.relative_path() << std::endl;
std::cout << "path.parent_path() : " << path.parent_path() << std::endl;
std::cout << "path.filename() : " << path.filename() << std::endl;
std::cout << "path.stem() : " << path.stem() << std::endl;
std::cout << "path.extension() : " << path.extension() << std::endl;
}
path.relative_path() : "../test_dir/1.txt"
path.parent_path() : "../test_dir"
path.filename() : "1.txt"
path.stem() : "1"
path.extension() : ".txt"
os.path
中提供了分割函数split()
以及dirname()
,basename()
。
def eg1_2():
"""路径分割"""
path = "../test_dir/1.txt"
print("os.path.split(path) : {}".format(os.path.split(path)))
print("os.path.dirname(path) : {}".format(os.path.dirname(path)))
print("os.path.basename(path) : {}".format(os.path.basename(path)))
os.path.split(path) : ('../test_dir', '1.txt')
os.path.dirname(path) : ../test_dir
os.path.basename(path) : 1.txt
路径拼接
filesystem::path
中重载了符号/
和/=
。
friend _LIBCPP_INLINE_VISIBILITY path operator/(const path& __lhs,
const path& __rhs) {
path __result(__lhs);
__result /= __rhs;
return __result;
}
void eg1_3() {
/*路径拼接*/
std::filesystem::path path = "../test_dir";
std::filesystem::path txt1_path = path / "1.txt";
std::filesystem::path txt2_path = path / "1_dir" / "2.txt";
std::cout << "txt1_path : " << txt1_path << std::endl;
std::cout << "txt2_path : " << txt2_path << std::endl;
path /= "1.txt";
std::cout << "path : " << path << std::endl;
}
txt1_path : "../test_dir/1.txt"
txt2_path : "../test_dir/1_dir/2.txt"
path : "../test_dir/1.txt"
os.path
中提供了join()
函数。
def eg1_3():
"""路径拼接"""
path = "../test_dir"
txt1_path = os.path.join(path, "1.txt")
txt2_path = os.path.join(path, "1_dir", "2.txt")
print("txt1_path : {}".format(txt1_path))
print("txt2_path : {}".format(txt2_path))
txt1_path : ../test_dir/1.txt
txt2_path : ../test_dir/1_dir/2.txt
- 注意,不同操作系统的分隔符不同,所以在Windows中运行结果如下。
txt1_path : ../test_dir\1.txt
txt2_path : ../test_dir\1_dir\2.txt
filesystem
vs. os
获取当前工作目录
filesystem
提供了获取当前路径的函数current_path()
,注意返回的是绝对路径。
void eg2_1() {
/*获取当前路径*/
std::filesystem::path current_path = std::filesystem::current_path();
std::cout << "current_path : " << current_path << std::endl;
}
current_path : "/Users/xxx/Github/intro_to_C-python/xxx/cmake-build-debug"
os
提供了函数getcwd()
。
def eg2_1():
"""获取当前路径"""
current_path = os.getcwd()
print("current_path : {}".format(current_path))
current_path : /Users/xxx/Github/intro_to_C-python/xxx
这里先展示一下目录树,方便理解后边的例子。
└── test_dir
├── 1.txt
└── 1_dir
├── 2.txt
└── empty_dir
返回指定目录下的所有文件/文件夹
filesystem
的类directory_iterator
可以实现该功能。
void eg2_2() {
/*返回指定目录下的所有文件/文件夹*/
std::filesystem::directory_iterator iter("../test_dir");
for(const auto &i : iter) {
std::cout << i.path() <<std::endl;
}
}
"../test_dir/1.txt"
"../test_dir/1_dir"
os
中提供了函数listdir()
。
def eg2_2():
"""返回指定目录下的所有文件/文件夹"""
for i in os.listdir("./test_dir"):
print(i)
1.txt
1_dir
递归返回指定目录下的所有文件/文件夹
filesystem
的类recursive_directory_iterator
可以实现该功能。
void eg2_3() {
/*递归返回指定目录下的所有文件/文件夹*/
std::filesystem::recursive_directory_iterator iter("../test_dir");
for(const auto &i : iter) {
std::cout << i.path() <<std::endl;
}
}
"../test_dir/1.txt"
"../test_dir/1_dir"
"../test_dir/1_dir/empty_dir"
"../test_dir/1_dir/2.txt"
os
中提供了函数walk()
。
def eg2_3():
"""递归返回指定目录下的所有文件/文件夹"""
for root, dirs, files in os.walk("./test_dir"):
print("root : {}, dirs : {}, files : {}".format(root, dirs, files))
root : ./test_dir, dirs : ['1_dir'], files : ['1.txt']
root : ./test_dir/1_dir, dirs : ['empty_dir'], files : ['2.txt']
root : ./test_dir/1_dir/empty_dir, dirs : [], files : []
判断路径是否存在
filesystem
提供了判断路径是否存在的函数exists()
。
void eg2_4() {
/*判断路径是否存在*/
bool exist = std::filesystem::exists("C:\\Users");
std::cout << "exist : " << exist << std::endl;
}
exist : 0
os.path
中提供了函数exists()
。
def eg2_4():
"""判断路径是否存在"""
path = "C:\\Users"
print("os.path.exists({}) : {}".format(path, os.path.exists(path)))
os.path.exists(C:\Users) : False
判断路径是文件还是目录
filesystem
提供了判断路径是文件还是目录的函数。(比较多)
inline _LIBCPP_INLINE_VISIBILITY bool is_block_file(file_status __s) noexcept {
return __s.type() == file_type::block;
}
inline _LIBCPP_INLINE_VISIBILITY bool is_block_file(const path& __p) {
return is_block_file(__status(__p));
}
inline _LIBCPP_INLINE_VISIBILITY bool is_block_file(const path& __p,
error_code& __ec) noexcept {
return is_block_file(__status(__p, &__ec));
}
inline _LIBCPP_INLINE_VISIBILITY bool
is_character_file(file_status __s) noexcept {
return __s.type() == file_type::character;
}
inline _LIBCPP_INLINE_VISIBILITY bool is_character_file(const path& __p) {
return is_character_file(__status(__p));
}
inline _LIBCPP_INLINE_VISIBILITY bool
is_character_file(const path& __p, error_code& __ec) noexcept {
return is_character_file(__status(__p, &__ec));
}
inline _LIBCPP_INLINE_VISIBILITY bool is_directory(file_status __s) noexcept {
return __s.type() == file_type::directory;
}
inline _LIBCPP_INLINE_VISIBILITY bool is_directory(const path& __p) {
return is_directory(__status(__p));
}
inline _LIBCPP_INLINE_VISIBILITY bool is_directory(const path& __p,
error_code& __ec) noexcept {
return is_directory(__status(__p, &__ec));
}
inline _LIBCPP_INLINE_VISIBILITY bool is_empty(const path& __p) {
return __fs_is_empty(__p);
}
inline _LIBCPP_INLINE_VISIBILITY bool is_empty(const path& __p,
error_code& __ec) {
return __fs_is_empty(__p, &__ec);
}
inline _LIBCPP_INLINE_VISIBILITY bool is_fifo(file_status __s) noexcept {
return __s.type() == file_type::fifo;
}
inline _LIBCPP_INLINE_VISIBILITY bool is_fifo(const path& __p) {
return is_fifo(__status(__p));
}
inline _LIBCPP_INLINE_VISIBILITY bool is_fifo(const path& __p,
error_code& __ec) noexcept {
return is_fifo(__status(__p, &__ec));
}
inline _LIBCPP_INLINE_VISIBILITY bool
is_regular_file(file_status __s) noexcept {
return __s.type() == file_type::regular;
}
inline _LIBCPP_INLINE_VISIBILITY bool is_regular_file(const path& __p) {
return is_regular_file(__status(__p));
}
inline _LIBCPP_INLINE_VISIBILITY bool
is_regular_file(const path& __p, error_code& __ec) noexcept {
return is_regular_file(__status(__p, &__ec));
}
inline _LIBCPP_INLINE_VISIBILITY bool is_socket(file_status __s) noexcept {
return __s.type() == file_type::socket;
}
inline _LIBCPP_INLINE_VISIBILITY bool is_socket(const path& __p) {
return is_socket(__status(__p));
}
inline _LIBCPP_INLINE_VISIBILITY bool is_socket(const path& __p,
error_code& __ec) noexcept {
return is_socket(__status(__p, &__ec));
}
inline _LIBCPP_INLINE_VISIBILITY bool is_symlink(file_status __s) noexcept {
return __s.type() == file_type::symlink;
}
inline _LIBCPP_INLINE_VISIBILITY bool is_symlink(const path& __p) {
return is_symlink(__symlink_status(__p));
}
inline _LIBCPP_INLINE_VISIBILITY bool is_symlink(const path& __p,
error_code& __ec) noexcept {
return is_symlink(__symlink_status(__p, &__ec));
}
inline _LIBCPP_INLINE_VISIBILITY bool is_other(file_status __s) noexcept {
return exists(__s) && !is_regular_file(__s) && !is_directory(__s) &&
!is_symlink(__s);
}
inline _LIBCPP_INLINE_VISIBILITY bool is_other(const path& __p) {
return is_other(__status(__p));
}
inline _LIBCPP_INLINE_VISIBILITY bool is_other(const path& __p,
error_code& __ec) noexcept {
return is_other(__status(__p, &__ec));
}
void eg2_5() {
/*判断路径是文件还是目录*/
std::filesystem::path file_path = "../test_dir/1.txt";
std::filesystem::path dir_path = "../test_dir/1_dir";
std::cout << "is_regular_file(file_path) : "
<< std::filesystem::is_regular_file(file_path)
<< std::endl;
std::cout << "is_directory(dir_path) : "
<< std::filesystem::is_directory(dir_path)
<< std::endl;
}
is_regular_file(file_path) : 1
is_directory(dir_path) : 1
os.path
中提供了函数isfile()
和isdir()
。
def eg2_5():
"""判断路径是文件还是目录"""
file_path = "./test_dir/1.txt"
dir_path = "./test_dir/1_dir"
print("os.path.isfile({}) : {}".format(file_path, os.path.isfile(file_path)))
print("os.path.isdir({}) : {}".format(dir_path, os.path.isdir(dir_path)))
os.path.isfile(./test_dir/1.txt) : True
os.path.isdir(./test_dir/1_dir) : True
返回绝对路径【神奇】
filesystem
中提供了函数absolute()
。
void eg2_6() {
/*返回绝对路径*/
std::filesystem::path path = "../test_dir";
std::filesystem::path abs_path = std::filesystem::absolute(path);
std::cout << "abs_path : " << abs_path << std::endl;
std::cout << "exists(abs_path) : " << std::filesystem::exists(abs_path) << std::endl;
}
abs_path : "/Users/xxx/Github/intro_to_C-python/xxx/cmake-build-debug/../test_dir"
exists(abs_path) : 1
- 在Windows系统中结果如下。
abs_path : "D:\\GitHub\\intro_to_C-python\\xxx\\test_dir"
exists(abs_path) : 1
os.path
中提供了函数abspath()
。
def eg2_6():
"""返回绝对路径"""
path = "../../-PyTorch-"
abs_path = os.path.abspath(path)
print("abs_path : {}".format(abs_path))
print("os.path.exists({}) : {}".format(abs_path, os.path.exists(abs_path)))
abs_path : /Users/xxx/Github/-PyTorch-
os.path.exists(/Users/xxx/Github/-PyTorch-) : True
filesystem
vs. shutil
shutil = shell + util
,对os进行一些补充。
文件拷贝
filesystem
中提供了copy_file()
函数,可以拷贝文件或空文件夹。
void eg3_1() {
/*文件拷贝*/
std::cout << "~~~~~~before copy_file~~~~~~" << std::endl;
for (const auto &i :std::filesystem::directory_iterator("../test_dir")) {
std::cout << i.path() << std::endl;
}
std::filesystem::copy_file("../test_dir/1.txt", "../test_dir/eg3_1.txt");
std::cout << "~~~~~~after copy_file~~~~~~" << std::endl;
for (const auto &i :std::filesystem::directory_iterator("../test_dir")) {
std::cout << i.path() << std::endl;
}
}
~~~~~~before copy_file~~~~~~
"../test_dir/1.txt"
"../test_dir/1_dir"
~~~~~~after copy_file~~~~~~
"../test_dir/eg3_1.txt"
"../test_dir/1.txt"
"../test_dir/1_dir"
shutil
中提供函数copyfile()
。
def eg3_1():
"""文件拷贝"""
print("~~~~~~before copy_file~~~~~~")
for i in os.listdir("./test_dir"):
print(i)
src_path = "./test_dir/1.txt"
dst_path = "./test_dir/eg3_1.txt"
shutil.copyfile(src_path, dst_path)
print("~~~~~~after copy_file~~~~~~")
for i in os.listdir("./test_dir"):
print(i)
~~~~~~before copy_file~~~~~~
1.txt
1_dir
~~~~~~after copy_file~~~~~~
eg3_1.txt
1.txt
1_dir
文件删除
filesystem
中提供了remove()
函数,可以删除文件或空文件夹。
void eg3_2() {
/*文件删除*/
std::cout << "~~~~~~before remove~~~~~~" << std::endl;
for (const auto &i :std::filesystem::directory_iterator("../test_dir")) {
std::cout << i.path() << std::endl;
}
std::filesystem::remove("../test_dir/eg3_1.txt");
std::cout << "~~~~~~after remove~~~~~~" << std::endl;
for (const auto &i :std::filesystem::directory_iterator("../test_dir")) {
std::cout << i.path() << std::endl;
}
}
~~~~~~before remove~~~~~~
"../test_dir/eg3_1.txt"
"../test_dir/1.txt"
"../test_dir/1_dir"
~~~~~~after remove~~~~~~
"../test_dir/1.txt"
"../test_dir/1_dir"
os
中提供了函数remove()
。
def eg3_2():
"""文件删除"""
print("~~~~~~before remove~~~~~~")
for i in os.listdir("./test_dir"):
print(i)
rm_path = "./test_dir/eg3_1.txt"
os.remove(rm_path)
print("~~~~~~after remove~~~~~~")
for i in os.listdir("./test_dir"):
print(i)
~~~~~~before remove~~~~~~
eg3_1.txt
1.txt
1_dir
~~~~~~after remove~~~~~~
1.txt
1_dir
路径拷贝
filesystem
中提供了copy()
函数,可以按照选项(是否递归)拷贝文件或文件夹。
void eg3_3() {
/*路径拷贝*/
std::cout << "~~~~~~before copy[1_dir]~~~~~~" << std::endl;
for (const auto &i :std::filesystem::directory_iterator("../test_dir/1_dir")) {
std::cout << i.path() << std::endl;
}
std::filesystem::copy("../test_dir/1_dir",
"../test_dir/eg3_3_dir",
std::filesystem::copy_options::recursive);
std::cout << "~~~~~~after copy[eg3_3_dir]~~~~~~" << std::endl;
for (const auto &i :std::filesystem::directory_iterator("../test_dir/eg3_3_dir")) {
std::cout << i.path() << std::endl;
}
}
~~~~~~before copy[1_dir]~~~~~~
"../test_dir/1_dir/empty_dir"
"../test_dir/1_dir/2.txt"
~~~~~~after copy[eg3_3_dir]~~~~~~
"../test_dir/eg3_3_dir/empty_dir"
"../test_dir/eg3_3_dir/2.txt"
shutil
提供了函数copytree()
。
def eg3_3():
"""路径拷贝"""
print("~~~~~~before copy[1_dir]~~~~~~")
for i in os.listdir("./test_dir/1_dir"):
print(i)
src_path = "./test_dir/1_dir"
dst_path = "./test_dir/eg3_3_dir"
shutil.copytree(src_path, dst_path)
print("~~~~~~after copy[eg3_3_dir]~~~~~~")
for i in os.listdir("./test_dir/eg3_3_dir"):
print(i)
~~~~~~before copy[1_dir]~~~~~~
empty_dir
2.txt
~~~~~~after copy[eg3_3_dir]~~~~~~
empty_dir
2.txt
递归删除
filesystem
中提供了remove_all()
函数,可以递归删除文件或文件夹。
void eg3_4() {
/*递归删除*/
std::filesystem::path dir_path = "../test_dir/eg3_3_dir";
std::cout << "exists(dir_path) : " << std::filesystem::exists(dir_path) << std::endl;
std::filesystem::remove_all(dir_path);
std::cout << "exists(dir_path) : " << std::filesystem::exists(dir_path) << std::endl;
}
exists(dir_path) : 1
exists(dir_path) : 0
shutil
提供了函数rmtree()
。
def eg3_4():
"""递归删除"""
dir_path = "./test_dir/eg3_3_dir"
print("os.path.exists({}) : {}".format(dir_path, os.path.exists(dir_path)))
shutil.rmtree(dir_path)
print("os.path.exists({}) : {}".format(dir_path, os.path.exists(dir_path)))
os.path.exists(./test_dir/eg3_3_dir) : True
os.path.exists(./test_dir/eg3_3_dir) : False