最近寫代碼有一個要遍歷目錄下的每一個文件並取得這個文件的絕對路徑的需求,
我們知道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目錄