自从大三做完三维激光扫描仪后再也木有用过C语言来编写代码了,更别提C++啦,去到新的公司对C++不熟悉的我,感谢组长收留(此处应该有一万滴眼泪飞奔)。
一开始我跟很多小盆友一样觉得文件夹管理类就写个函数遍历一下目录,没什么特别重要的,但是后面的《机器人视觉初级系列》的代码中大量遍历文件夹这个功能,一开始对C++的类封装简直不熟悉(白痴)的状态,Good good study, day day up。
任务:
使用c++编写一个文件夹管理类:
- 可以递归遍历指定路径的所有文件;
- 编写makefile文件进行编译;
- 使用makefile文件;
既然对C++类不熟悉,那么开始进阶的我当然是选择使用函数来实现。值得注意的,在Linux文件系统里面,几乎你看到的都是文件,目录其实全名叫“目录文件”directory,平时看到的叫“普通文件”,当然还有不是很常见的“软连接文件”symbolic,“块文件”block,“字符文件”character。这样的编排定义方式很方便对目录和目录内的文件进行遍历了。
C++递归遍历目录内文件函数:
/*
* description: 遍历目录和目录中的文件夹
*/
int inDir(char *path) {
struct dirent *env = NULL;// dirent 目录环境结构体
struct stat statbuf; // stat 文件状态结构体
DIR *faceDir;
// 处理目录错误
if ((faceDir = opendir(path)) == NULL) {
cout << "canot open directory:" << path << endl;
return -1;
}
chdir(path);
while ((env = readdir(faceDir)) != NULL) {// 遍历目录内文件
lstat(env->d_name, &statbuf); // get file state
if (S_ISDIR(statbuf.st_mode)) {// 检查是否目录
// when the file is directory
if (strcmp(env->d_name, ".") == 0 || strcmp(env->d_name, "..") == 0)
continue; // 去掉"." ".."的标识文件
cout << "\nEnter DIR: " << path << endl;
inDir(env->d_name);// 如果是目录的话进入递归
} else {
// when the file is file
if (strcmp(env->d_name, ".DS_Store") == 0) {
continue; // just appear in MACOS
}
cout << env->d_name << endl;
}
}
cout << "\n" << endl;
chdir("..");// 没有更多文件,递归完成,返回上一层菜单
return 0;
}
int main(int argc, const char *argv[]) {
char dir_path[] = "/Users/chenzomi/Book/Others";
inDir(dir_path);
return 0;
}
运行结果:
实际文件:
上面只是简单的实现一个函数对文件遍历,那么文件遍历的类实现呢?这个时候开始来学习C++类。编写下面代码的时候我学习了:
- 构造函数的使用
- 构造函数重载
- 构造函数传参使用:冒号
- 如何定义类和类的使用
- 类成员函数递归的时候,需要注意参数的位置
因此,下面实现C++递归遍历目录文件:
class traversalDir{
public:
// 构造函数的作用:初始化对象的数据成员
traversalDir(){};
traversalDir(char *path):path(path){inDir(path);}
traversalDir(char *path, char *pattern):path(path), pattern(pattern){}
int inDir(char *path);
private:
struct dirent *env = NULL;// dirent 目录环境结构体
struct stat statbuf; // stat 文件状态结构体
char *path;
char *pattern;
};
/*
* description: 遍历目录和目录中的文件夹
*/
int traversalDir::inDir(char *path) {
DIR *faceDir;
env = NULL;
// 处理目录错误
if ((faceDir = opendir(path)) == NULL) {
cout << "canot open directory:" << path << endl;
return -1;
}
chdir(path);
while ((env = readdir(faceDir)) != NULL) {// 遍历目录内文件
lstat(env->d_name, &statbuf); // get file state
if (S_ISDIR(statbuf.st_mode)) {// 检查是否目录
// when the file is directory
if (strcmp(env->d_name, ".") == 0 || strcmp(env->d_name, "..") == 0)
continue; // 去掉"." ".."的标识文件
cout << "\nEnter DIR: " << path << endl;
inDir(env->d_name);// 如果是目录的话进入递归
} else {
// when the file is file
if (strcmp(env->d_name, ".DS_Store") == 0){
continue;
}
cout << env->d_name << endl;
}
}
cout << "\n" << endl;
chdir("..");// 没有更多文件,递归完成,返回上一层菜单
return 0;
}
int main(int argc, const char *argv[]) {
char dir_path[] = "/Users/chenzomi/Book/Others";
traversalDir t(dir_path);
return 0;
}
这里我遇到一个问题,一开始是DIR *faceDir 放在类的private里面,然后程序进入第一次递归之后就退出了,并没有实现递归的返回。组长给分析了一下代码发现是faceDir不是局部变量,是类变量,所以没有实现递归的返回,为什么会这样呢,因为进入递归之后保存的是上一次执行函数的变量,返回之后继续上一次的执行状态继续往下执行,而faceDir定义为类变量的时候进入递归之后并没有保存该变量,而是由类来保存,那么退出递归之后就找不到faceDir变量,因此faceDir需要定义在函数里面。
最后的执行效果: