2016-10-01 52 views
0

我有一個編程問題,希望有人能幫助我。我試圖在工作中學習C編程,併爲自己設置了一個小項目,其中包括讀取包含所有子目錄的文件樹,以獲取有關每個文件的信息。檢查目錄路徑以「。」,「..」結尾

我得到的問題是我的程序不會忽略目錄路徑以/結尾。或/ ..和當它打印所有的目錄時,我想在可讀性的子目錄前面留出空間。

所以誤差在這部分發生:

int isDir(const char *parent, char *name) { 

    struct stat st_buf; // file info 
    char buf[BUF_SIZE]; 

    if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { 
     return 0; 
    } 
    char *path = malloc(strlen(name) + strlen(parent) + 2); 
    //sprintf(char *buf, const char *format, [arg1],[arg2],...) 
    sprintf(path, "%s/%s", parent, name); 
    stat(path, &st_buf); // 

    return S_ISDIR(st_buf.st_mode); //directory 
} 

而這主要和列表功能:

int list(const char *name) { 
    DIR *dirp = opendir(name); 
    struct dirent *dentry; 
    char buf[BUF_SIZE]; 

    while ((dentry = readdir(dirp)) != NULL) { 
    char *dir_name = dentry->d_name;   

      printf(" %s\n", dir_name); 

     //if it's dir, then go into dir 
     if (isDir(name, dir_name)) { //name : parent, dir_name : child 
      chdir(dir_name); 
      getcwd(buf, BUF_SIZE); 
      list(buf); 
     } 
    } 
    closedir(dirp); 
} 

int main() 
{ 
    list("."); 
    return 0; 
} 

的結果是這樣的:

hm1.c 
Data 
lab1.txt 
result1 
lab3.txt 
. 
.. 
. 
.. 
result2 
lab3.txt 
. 
.. 
result3 
lab3.txt 
. 
.. 
a.c 
. 
.. 
a.out 

結果I wan噸至打印

hm1.c 
Data 
    lab1.txt 
    result1 
     lab3.txt 
    result2 
     lab3.txt 
    result3 
     lab3.txt 
a.c 
a.out 
+1

您的'isDir()'函數每次在'name'中調用'.'或'..'以外的內存都會泄漏內存。你也應該至少錯誤地檢查'malloc()'和'opendir()' - 也可以''chdir()'和'getcwd()'。 –

+3

在打印任何內容之前,您需要額外檢查'.'和'..',並且您可能需要將其他深度參數傳遞給'list',以便您可以基於此進行縮進。 –

+0

「printf(」%s \ n「,dir_name)中使用了'dir_name';'defined,set等? 'file_mode'和'my_passwd'變量也不被使用。請參閱製作MCVE([MCVE])的指導原則。他們讓人們更容易幫助你。您的代碼顯示似乎從原來的縮減,但不是最小化和不可驗證。 –

回答

1

isDir將返回真/假它返回false(或零),如果你有. OE ..,然後在其他情況下,真/假的S_ISDIR

您真正需要的功能是返回SKIP,isFILE或isDIR三個值中的一個,然後根據此值編寫打印邏輯。

您還需要修復您的內存泄漏

還要注意的是chdir(dir_name);改變過程的實際目錄,所以一旦你從list你的循環中返回,您將不再能夠打開文件或目錄,你遍歷(因爲你現在是在不同的目錄)

這將解決您的問題,並打印的格式,你想

enum { doSkip, isFile, isDir } testDir(char *path, char *name) 
{ 
    struct stat st_buf;   
    if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0) { 
     return doSkip; 
    } 
    stat(path, &st_buf); 
    if (S_ISDIR(st_buf.st_mode)) 
     return isDir; 
    return isFile; 
} 

void list(const char *path, int indentlevel) 
{ 
    DIR *dirp = opendir(path); 
    struct dirent *dentry; 
    char buf[10000]; // Lets just make the buffer sufficently big for this example 
    if (!dirp) { 
     printf("%*sNo access\n",indentlevel,""); 
     return; 
    } 

    while ((dentry = readdir(dirp)) != NULL) { 

     sprintf(buf,"%s/%s", path, dentry->d_name); 
     switch (testDir(buf,dentry->d_name)) { 
     case doSkip: 
      /* do nothing */ 
      break; 
     case isDir: 
      printf("%*s%s:\n",indentlevel,"",dentry->d_name); 
      list(buf,indentlevel+4); 
      break; 
     case isFile: 
      printf("%*s%s\n",indentlevel,"",dentry->d_name); 
      break; 
     } 
    } 
    closedir(dirp); 
} 

int main() 
{ 
    list(".", 0); 
    return 0; 
} 
0

另一種方式做到這一點,如果你」重新願意去C++,是使用std::experimental::filesystem,也是(大部分)被稱爲Boost.Filesystem。有了這個,你會這樣做:

#include <experimental/filesystem> // Could substitute <boost/filesystem.hpp> 
#include <boost/range/iterator_range.hpp> 
#include <iostream> 

using namespace std::experimental; 

int main(int argc, char *argv[]) 
{ 
    const auto path = filesystem::path{ argc > 1 ? argv[1] : "." }; 

    if(filesystem::is_directory(path)) 
    { 
     std::cout << path << " is a directory containing:\n"; 

     for(const auto& entry : boost::make_iterator_range(filesystem::recursive_directory_iterator{path}, {})) 
     { 
      std::cout << entry << "\n"; 
     } 
    } 
} 

看到它運行here。請注意,目錄迭代器會自動跳過...

+0

你的答案是C++ - OP正在問一個C問題 – Soren

+1

對,這就是爲什麼我說「如果你願意去C++」。由於OP已將此任務設置爲自己,因此C似乎並不是一項艱難的要求,而且C++具有跨平臺,幾乎標準的設備來處理它。事實上,它明確依賴於Linux/POSIX功能。我的解決方案不需要,並且需要相當少的代碼才能正確維護。 – metal

+0

我想知道如果我可以讓你的例子工作來理解遞歸迭代器的* magic *,並且看看輸出是否可以按照規範格式化 - 但是我得到了一個提升鏈接問題的兔子洞像這樣一個http://stackoverflow.com/questions/15634114/cant-link-program-using-boost-filesystem-我必須說,我從來沒有一個推動的粉絲,所以即時放棄,而無法做到它運行 – Soren