最近写代码有一个要遍历目录下的每一个文件并取得这个文件的绝对路径的需求,
我们知道linux c++中有system命令所以我在代码中 先生成了一个log,然后去读log文件的每一行文件名,然后给存储下来.
1 void getFiles( vecotr<string> vecFileNames) 2 { 3 4 string path = "/home/yongchao/*.txt"; 5 6 system("ls" + path + " > temp.log"); 7 8 ifstream ifs("/home/yongchao/temp.log") //变量log里面每一个文件 9 if (ifs.fail()) 10 { 11 return; 12 } 13 14 string fileName; 15 while (getline(ifs, fileName)) 16 { 17 vecFileNames.push_back("/home/yongchao/" + fileName); 18 } 19 20 ifs.close(); 21 ifs.clear(); 22 return; 23 }
结果,可想而知,被项目经理狠狠的批评了一顿,说我太懒了,然后又被同事嘲笑的很是羞愧难当....首先是这个不能递归的把每一个子目录文件都保存;其次同事说,如果做临时测试你可以这些写,但是做项目不能这么干... 痛定思痛,乖乖的去网上搜索的linux c++的遍历目录文件名的解决方法.
1 #include<sys/types.h> 2 #include<sys/stat.h> 3 #include<dirent.h> // /usr/include/dirent.h 4 #include<string> 5 #include<iostream> 6 using namespace std; 7 8 int getAbsoluteFiles(string directory, vector<string>& filesAbsolutePath) //参数1[in]要变量的目录 参数2[out]存储文件名 9 { 10 DIR* dir = opendir(directory.c_str()); //打开目录 DIR-->类似目录句柄的东西 11 if ( dir == NULL ) 12 { 13 cout<<directory<<" is not a directory or not exist!"<<endl; 14 return -1; 15 } 16 17 struct dirent* d_ent = NULL; //dirent-->会存储文件的各种属性 18 char fullpath[128] = {0}; 19 char dot[3] = "."; //linux每个下面都有一个 . 和 .. 要把这两个都去掉 20 char dotdot[6] = ".."; 21 22 while ( (d_ent = readdir(dir)) != NULL ) //一行一行的读目录下的东西,这个东西的属性放到dirent的变量中 23 { 24 if ( (strcmp(d_ent->d_name, dot) != 0) 25 && (strcmp(d_ent->d_name, dotdot) != 0) ) //忽略 . 和 .. 26 { 27 if ( d_ent->d_type == DT_DIR ) //d_type可以看到当前的东西的类型,DT_DIR代表当前都到的是目录,在usr/include/dirent.h中定义的 28 { 29 30 string newDirectory = directory + string("/") + string(d_ent->d_name); //d_name中存储了子目录的名字 31 if( directory[directory.length()-1] == '/') 32 { 33 newDirectory = directory + string(d_ent->d_name); 34 } 35 36 if ( -1 == getAbsolutFiles(newDirectory, filesAbsolutePath) ) //递归子目录 37 { 38 return -1; 39 } 40 } 41 else //如果不是目录 42 { 43 string absolutePath = directory + string("/") + string(d_ent->d_name); //构建绝对路径 44 if( directory[directory.length()-1] == '/') //如果传入的目录最后是/--> 例如a/b/ 那么后面直接链接文件名 45 { 46 absolutePath = directory + string(d_ent->d_name); // /a/b/1.txt 47 } 48 filesAbsolutePath.push_back(absolutePath); 49 } 50 } 51 } 52 53 closedir(dir); 54 return 0; 55 }
<<unix环境高级编程>>
http://blog.csdn.net/zhuyi2654715/article/details/7605051
1 struct __dirstream 2 3 { 4 5 void* __fd; 6 7 char* __data; 8 9 int __entry_data; 10 11 char* __ptr; 12 13 int __entry_ptr; 14 15 size_t __allocation; 16 17 size_t __size; 18 19 __libc_lock_define(, __lock) 20 21 }; 22 23 typedef struct __dirstream DIR;
DIR结构体类似于FILE,是一个内部结构,有以下几个常用函数
DIR* opendir(const char* pathname); //
struct dirent* readdir(DIR* dp); //循环读取目录中的资讯
void rewinddir(DIR* dp); //重新读取目录资讯
int closedir(DIR* dp);
long telldir(DIR* dp);
void seekdir(DIR* dp, long loc);
目录文件(directory file): 这种文件包含了其他文件的名字以及指向与这些文件有关的信息的指针.
dirent 不仅仅指向目录,还指向目录中的具体文件
struct dirent { long d_info; //inode number 索引节点号 off_t d_off; //offset to this dirent 在目录文件中的偏移量 unsigned short d_reclen; //length of this d_name 文件长度,注意这里的长度不是文件大小,大小和长度是两回事,你可以用lseek将文件长度移的很长,但大小其实还是那么大 unsigned char d_type; //the type of d_name 文件类型 char d_name[NAME_MAX+1]; //file name(null-terminated) 文件名,最初255 }
从上述定义看出,dirent结构体存储的关于文件的信息很少,所以dirent同样也是起着一个索引的作用,如果想获得类似 ls -l那种效果的文件信息, 必须要要下面的stat函数
int stat(const char* file_name, struct stat* buf);
readdir函数会将读取到的文件名存储在结构体dirent的d_name成员中
而stat函数的作用就是获取d_name文件的详细信息,并将这些详细信息存储在下面的stat结构中
struct stat { mode_t st_mode; //文件访问权限 ino_t st_ino; //索引节点号 dev_t st_dev; //文件使用的设备号 dev_t st_rdev; //设备文件的设备号 nlink_t st_nlink; //设备的硬连接数 uid_t st_uid; //所有者用户识别号 gid_t st_gid; //组识别号 off_t st_size; //以字节为单位的文件容量 time_t st_atime; //最后一次访问该文件的时间 time_t st_mtime; //最后一次修改该文件的时间 time_t st_ctime; //最后一次改变该文件状态的时间 blksize_t st_blksize; //包含该文件的磁盘块的大小 blkcnt_t st_blocks; //该文件所占的磁盘块 };
如果我们想获取a目录下b文件的详细信息的流程:
opendir函数打开目录a, 返回指向目录a的DIR结构体c
调用readdir(c)函数读取目录下所有文件(包括子目录), 返回指向目录a下所有文件的dirent结构体d
遍历d,调用stat(d->name, stat* e) 来获取每个文件的详细信息,存储在stat结构体e中
下面是一个打印目录下所有文件和目录的程序
再介绍一些其它的跟目录操作有关的函数
#include<unitstd.h>
//获得当前目录名称
char* getcwd(char* buf, size_t size); -->buf将会返回当前目录名称. 任何错误的发生,将会返回NULL.如果路径长度超过size, errno为ERANGE.getcwd返回的值永远没有symbol link的
char* getcwd(char* buf); --->getcwd是个危险的函数,一般都会强烈建议不要用,因为你无法确定最长的目录长度为多少.
//获得系统目录最大长度
long pathconf(char* path, int flag);
//改变目前所在目录
chdir/fchdir/chroot
int chdir(const char* pathname);--->根据pathname变更当前的所在目录,它只改变该程序的所在目录
int fchidr(int fd);--->根据已开启的fd(file descriptor)目录来变更
int chroot(const char* path);--->改变该程序的根目录所在.
//更改当前目录到上一级目录 if (chdir("..") == -1) { perror("could not change current working directory\n"); return; }
#include<sys/stat.h>
#include <sys/types.h>
int mkdir(const char* dirname, mode_t mode); --->创建新目录出来,如果此目录或者档案已存在,则操作失败 例如 mkdir("/home/yongchao", 0755); //0755的0表示八进制
#incude<unistd.h>
int rmdir(char* pathname); --->删除pathname目录