1. 程式人生 > >在Linux下和Windows下遍歷目錄的方法及如何達成一致性操作

在Linux下和Windows下遍歷目錄的方法及如何達成一致性操作

    最近因為測試目的需要遍歷一個目錄下面的所有檔案進行操作,主要是讀每個檔案的內容,只要知道檔名就OK了。在Java中直接用File類就可以搞定,因為Java中使用了組合模式,使得客戶端對單個檔案和資料夾的使用具有一致性,非常方便。但在C中就不一樣了,而且在不同的平臺下使用方法也不同。在Linux下實現該功能就非常方便,因為自帶有API庫,幾個函式用起來得心應手(雖然有些小問題,後面說),在Windows下實現就不是那麼方便,雖然也有自己的API,但用法有些晦澀難懂,因為沒有封裝起來,需要自己一步一步進行操作,因為用的是Windows API庫函式所以如果對Windows程式設計不熟悉的話,照搬網上的程式碼錯了也不易除錯。為此,我把這些操作都封裝成類似Linux下的庫函式,一方面簡化透明瞭操作,另一方面(也許更重要)就是移植性,這樣將包含該功能的程式從Windows上移植到Linux下就無需改動程式碼了(刪掉實現封裝的檔案,因為Linux下自帶了),當然從Linux下移植到Windows下同樣方便(增加實現封裝的檔案即可),這就是所謂的OCP原則吧(開放封閉原則,具體見:)。好了,首先看下Linux下是如何實現這個功能的。

一、Linux下遍歷目錄的方法

 Linux下實現目錄操作的API函式都在標頭檔案dirent.h中,擷取部分該檔案內容如下:

/** structure describing an open directory. */
typedef struct _dirdesc {
    int    dd_fd;          /** file descriptor associated with directory */
    long    dd_loc;        /** offset in current buffer */
    long    dd_size;       /*
* amount of data returned by getdirentries */ char *dd_buf; /** data buffer */ int dd_len; /** size of data buffer */ long dd_seek; /** magic cookie returned by getdirentries */ long dd_rewind; /** magic cookie for rewinding */ int dd_flags; /*
* flags for readdir */ struct pthread_mutex *dd_lock; /** lock */ struct _telldir *dd_td; /** telldir position recording */ } DIR; typedef void * DIR; DIR *opendir(const char *); DIR *fdopendir(int); struct dirent *readdir(DIR *);
void     seekdir(DIR *, long);
long     telldir(DIR *);
void rewinddir(DIR *); int closedir(DIR *);

struct dirent
{
     long d_ino;              /* inode number*/
     off_t d_off;             /* offset to this dirent*/
     unsigned short d_reclen; /* length of this d_name*/
     unsigned char d_type;    /* the type of d_name*/
     char d_name[1];          /* file name (null-terminated)*/
};

關鍵部分就是DIR這個結構體的定義,包括檔案描述符、緩衝區偏移、大小、緩衝區內容等,下面定義的就是具體的目錄操作函數了,有開啟目錄、讀目錄、重置讀取位置、關閉目錄等,這裡我所需要的就是開啟、讀和關閉這三個最基本的目錄操作,下面是使用例子:

#include <stdio.h> 
#include <stdlib.h>    
#include <string.h>  
#include <dirent.h> 

#define MAX_LEN 65535

int main(void) 
{ 
    DIR *dir; 
    struct dirent *ptr; 
    char *flow[MAX_LEN];
    int num = 0, i = 0;
   
    if ((dir=opendir("./data")) == NULL) 
    { 
        perror("Open dir error..."); 
        exit(1);        
    } 
    // readdir() return next enter point of directory dir
    while ((ptr=readdir(dir)) != NULL) 
    { 
        flow[num++] = ptr->d_name;
//      printf("%s\n", flow[num - 1]);
    } 

    for(i = 0; i < num; i++)
    {
        printf("%s\n", flow[i]);
    }
   
    closedir(dir); 
}

執行結果如下:

一看這結果就不對,輸出的都是同一個檔名(最後一個檔案的檔名), 哪裡出了問題呢?將程式碼中// printf("%s\n", flow[num - 1]);這行註釋去掉再執行,發現註釋處輸出的是正確的,兩者都是輸出的flow陣列元素怎麼結果不一樣呢?經過除錯發現是flow[num++] = ptr->d_name;這句程式碼的問題,因為這是引用拷貝(地址拷貝),所有的flow元素全部指向同一個物件ptr->d_name,雖然ptr->d_name物件每次的內容不同(也就是前面正確輸出的原因),但所有內容都共享一個地址,用一個簡單的圖說明就是:

當然這個問題也比較好解決,也是比較常見的問題,用字串拷貝或記憶體拷貝就行了,給flow每個元素重新申請一塊記憶體。

#include <stdio.h> 
#include <stdlib.h>    
#include <string.h>  
#include <dirent.h> 

#define MAX_LEN 65535

int main(void) 
{ 
    DIR *dir; 
    struct dirent *ptr; 
    char *flow[MAX_LEN];
    int num = 0, i = 0;
   
    if ((dir=opendir("./data")) == NULL) 
    { 
        perror("Open dir error..."); 
        exit(1);        
    } 
    // readdir() return next enter point of directory dir
    while ((ptr=readdir(dir)) != NULL) 
    { 
        flow[num] = (char*)malloc(sizeof(char));
        strcpy(flow[num], ptr->d_name);
        num++;
    } 

    for(i = 0; i < num; i++)
    {
        printf("%s\n", flow[i]);
    }
   
    closedir(dir); 
}

 最終結果就正確了。

二、Windows下遍歷目錄的方法

 在Windows下就比較麻煩了,所要用到的函式都在windows.h中,Windows程式設計本來就比較繁瑣,下面就不一一介紹所用到的函數了,直接給出封裝的過程。

1. 首先模擬Linux下自帶的標頭檔案dirent.h

不同的是DIR中去掉了一些不需要的屬性,及只定義了三個我所需要的操作(按需定義)。

// dirent.h
#ifndef _SYS_DIRENT_H
#define _SYS_DIRENT_H typedef struct _dirdesc { int dd_fd; /** file descriptor associated with directory */ long dd_loc; /** offset in current buffer */ long dd_size; /** amount of data returned by getdirentries */ char *dd_buf; /** data buffer */ int dd_len; /** size of data buffer */ long dd_seek; /** magic cookie returned by getdirentries */ } DIR; # define __dirfd(dp) ((dp)->dd_fd) DIR *opendir (const char *); struct dirent *readdir (DIR *); void rewinddir (DIR *); int closedir (DIR *); #include <sys/types.h> struct dirent { long d_ino; /* inode number*/ off_t d_off; /* offset to this dirent*/ unsigned short d_reclen; /* length of this d_name*/ unsigned char d_type; /* the type of d_name*/ char d_name[1]; /* file name (null-terminated)*/ }; #endif

2. 三個目錄操作函式的實現

當然這是最關鍵的部分,我不知道Linux下是怎麼實現的(找了下沒找到),Windows下實現如下,主要是FindFirstFile()和FindNextFile()這兩個Windows函式,對Windows程式設計不精,也不好解釋什麼,需要搞明白為啥這樣實現請上網搜或MSDN。

// dirent.c
#include <stdio.h> #include <windows.h> #include "dirent.h" static HANDLE hFind; DIR *opendir(const char *name) { DIR *dir; WIN32_FIND_DATA FindData; char namebuf[512]; sprintf(namebuf, "%s\\*.*",name); hFind = FindFirstFile(namebuf, &FindData ); if(hFind == INVALID_HANDLE_VALUE) { printf("FindFirstFile failed (%d)\n", GetLastError()); return 0; } dir = (DIR *)malloc(sizeof(DIR)); if(!dir) { printf("DIR memory allocate fail\n"); return 0; } memset(dir, 0, sizeof(DIR)); dir->dd_fd = 0; // simulate return return dir; } struct dirent *readdir(DIR *d) { int i; static struct dirent dirent; BOOL bf; WIN32_FIND_DATA FileData; if(!d) { return 0; } bf = FindNextFile(hFind,&FileData); //fail or end if(!bf) { return 0; } for(i = 0; i < 256; i++) { dirent.d_name[i] = FileData.cFileName[i]; if(FileData.cFileName[i] == '\0') break; } dirent.d_reclen = i; dirent.d_reclen = FileData.nFileSizeLow; //check there is file or directory if(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { dirent.d_type = 2; } else { dirent.d_type = 1; } return (&dirent); } int closedir(DIR *d) { if(!d) return -1; hFind=0; free(d); return 0; }

3. 使用方法

與Linux下使用一模一樣,不需要改動一句程式碼就可應用,但卻發現了與Linux下自帶實現同樣的問題,即也是引用拷貝,如下。

相關推薦

LinuxWindows目錄方法如何達成一致性操作

    最近因為測試目的需要遍歷一個目錄下面的所有檔案進行操作,主要是讀每個檔案的內容,只要知道檔名就OK了。在Java中直接用File類就可以搞定,因為Java中使用了組合模式,使得客戶端對單個檔案和資料夾的使用具有一致性,非常方便。但在C中就不一樣了,而且在不同的平臺下使用方法也不同。在Linux下實現該

LinuxWindows的效能監控

Linux -- uptime命令: top命令:可以知道每個程序佔CPU的情況 total 程序總數 running 正在執行的程序數 sleeping 睡眠的程序數 stopped 停止的程序數 zombie 殭屍程序數 Cpu(s): 0.1% us 使用者空間佔用C

遊戲引擎選擇、MacWindowsUnrealEngine 4體驗對比

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

佇列、棧遞迴目錄

棧 棧是一種記憶體結構,先進後出,後進先出。python中沒有棧的概念,我們目前只能仿寫。   # 模擬棧結構 stack = [] # 入棧(新增元素) stack.append("A") print(stack) stack.append("B") print(st

os.walkos.listdir目錄比較

假設存在下面的目錄和檔案結構:/a ----> /b ----> 1.py,2.py    ----> /c  ----> 3.py , 4.py    ----> 5.py    ----> 6.pyos.walk()執行下面的測試程式碼

php佇列方式遞迴方式目錄檔案子目錄

如果目錄很多,推薦佇列方式,遞迴方式會慢,慢的原因:遞迴的實現是通過呼叫函式本身,函式呼叫的時候,每次呼叫時要做地址儲存,引數傳遞等 <?php   //遞迴方式 function read_dir($dir){       $fil

iOS中數組方法比較

結果 keyword div standard c語言 tracking dsm track 代碼 數組遍歷是編碼中很常見的一種需求,我們來扒一拔iOS裏面都有什麽樣的方法來實現,有什麽特點。 因為ios是兼容C語言的,所以c語言裏面的最最常見的for循環遍

C++實現LinuxWindows指定目錄的檔案

一、Linux下遍歷方法 方法非常簡單,這裡不多說了,可以直接看程式碼 #include <dirent.h>//遍歷系統指定目錄下檔案要包含的標頭檔案 #include <iost

C/C++目錄的所有文件(Windows/Linux篇,超詳細)

檢查 msd 字符 size tro 也會 結構 () alt 前面的一篇文章我們講了用Windows API遍歷一個目錄下的所有文件,這次我們講用一種Windows/Linux通用的方法遍歷一個目錄下的所有文件。 Windows/Linux的IDE都會提供一個頭文件—

windowlinux目錄的比較

window下,遍歷目錄主要是用FindFirstFile和FindNextFile,而linux下是用opendir和readdir實現 void scanFile(char *szDir) {

linux 的文件目錄操作目錄

ges div strcmp pen fprintf pwd edi while font   通過遞歸調用讀取目錄和文件信息去遍歷整個目錄:   示例代碼: 1 #include <unistd.h> 2 #include <stdio.h>

python目錄的所有檔案目錄詳細介紹

目錄結構如下圖: test---a------d------g--------g.txt test---a------d------a.txt test---a------e --------b --------c --------1.txt --------2.tx

os.walk 目錄目錄檔案

python中os.walk是一個簡單易用的檔案、目錄遍歷器,可以幫助我們高效的處理檔案、目錄方面的事情。 1.載入 要使用os.walk,首先要載入該函式 可以使用以下兩種方法 import os from os im

LinuxWindows檔案目錄的相關屬性操作

我們知道C/C++都提供了標準的檔案I/O庫以便我們對檔案進行讀寫。但我們無法通過標準的I/O庫對檔案系統進行更進一步的操作。因為這設計到具體作業系統中檔案系統的設計。在Linux和Windows程

linux快速目錄方法

個人使用nftw()遍歷指定目錄的大小: 具體用法請參照下文說明 #include <stdio.h> #include <ftw.h> #include <dirent.h> #include <sys/stat.h> #

linux目錄方法總結

前幾天需要實現對整個目錄樹的遍歷,查閱了相關的一些資料。開始找到的原始的方法是使用readdir()與lstat()函式實現遞迴遍歷,後來發現linux對於目錄遍歷這種最常用的操作已經提供了很完善的介面:ftw()與nftw()。下面就這兩種方法具體說明一下。1、手動實現遞迴

目錄所有資料夾檔案-------遞迴刪除空目錄

遍歷資料夾下所有檔案有兩種方法備註p為列印函式相當於print_r(),var_dump()的友好輸出第一種://遍歷資料夾下所有檔案和目錄//opendir():將目錄下的檔案已資源的形式儲存 //r

Linux如何新增附加包含目錄依賴庫(windowsvisual studio中類比)

一、新增附加包含目錄       法1:-I path(path為標頭檔案路徑)       法2:將標頭檔案拷貝到 /usr/local/include中       相當於VS中新增包含路徑,如下

linuxwindows安裝python拓展包requirement.txt安裝類庫

too tor == 引導 -cp mod flask utf addition http://blog.csdn.net/pipisorry/article/details/39902327python拓展包安裝直接安裝拓展包默認路徑:Unix(Linux)默認路徑:/

mysql數據庫在Linuxwindows免安裝實現以及框架開發碰到的問題

自動啟動 過程 root mil 是否 call 啟動頁 同時 ice 2017年7月23號下午5:20分,上周我根據自己的實際情況,總結了mysql數據庫在windows系統下和linux系統下免安裝版本的實現,以及在項目開發中遇到的數據庫報錯,今天整理出來,以供日後學習