2016-10-01 14 views
0

Ich habe ein Programmierproblem, dass ich hoffe, dass jemand da draußen kann mir helfen. Ich versuche C-Programmierung für eine Aufgabe bei der Arbeit zu lernen, und ich habe mir ein kleines Projekt gesetzt, das darin besteht, einen Dateibaum mit allen Unterverzeichnissen zu lesen, die Informationen über jede Datei erhalten.Überprüfung der Verzeichnispfade endet mit ".", ".."

Das Problem, das ich bekomme, ist, dass mein Programm ignoriert den Verzeichnispfad endet entweder mit /. oder/.. und wenn es alle Verzeichnisse druckt, möchte ich Platz vor den Unterverzeichnissen für die Lesbarkeit geben.

so wird der Fehler in diesem Teil aufgetreten:

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 
} 

Und das ist Haupt-und Listenfunktion:

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; 
} 

Das Ergebnis ist wie folgt aus:

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

Ergebnis ich wan t drucken

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

Ihre 'isDir()' Funktion löscht den Speicher jedes Mal, wenn sie mit einem anderen Namen als '.' oder' ..' in 'name' aufgerufen wird. Sie sollten auch 'malloc()' und 'opendir()' mindestens prüfen - wohl auch 'chdir()' und 'getcwd()'. –

+3

Bevor Sie etwas drucken, benötigen Sie eine zusätzliche Überprüfung für '.' und' ..', und Sie werden wahrscheinlich einen zusätzlichen Tiefenparameter an 'list' übergeben wollen, damit Sie darauf einen Einzug erstellen können. –

+0

Wo ist 'dir_name' in' printf ("% s \ n", dir_name); 'definiert, gesetzt, etc? Die Variablen 'file_mode' und' my_passwd' werden ebenfalls nicht verwendet. Bitte beachten Sie die Richtlinien zur Erstellung eines MCVE ([MCVE]). Sie erleichtern es den Menschen, Ihnen zu helfen.Ihr Code scheint von Ihrem Original reduziert zu sein, aber nicht minimiert und nicht überprüfbar. –

Antwort

1

Ihr isDir kehrt wahr/falsch, wo es gibt false zurück (oder Null), wenn Sie . oe .. und dann die wahr/falsch Wert von S_ISDIR in anderen Fällen

Was Sie wirklich brauchen, ist die Funktion, einen der 3 Werte SKIP, isFILE oder isDIR zurückzugeben und dann Ihre Drucklogik darauf zu schreiben.

Sie müssen auch Ihre Speicherlecks

auch beheben beachten Sie, dass chdir(dir_name); das aktuelle Verzeichnis des Prozesses ändert, so dass, sobald Sie von list innerhalb Ihrer Schleife zurückkehren werden Sie nicht mehr in der Lage sein, die Dateien oder Verzeichnisse zu öffnen, Sie sind Schleifen über (weil Sie jetzt in einem anderen Verzeichnis) sind

Diese Ihre Probleme beheben und das Format drucken Sie

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

eine andere Möglichkeit, es zu tun, wenn Sie‘ re bereit, nach C++ zu gehen, ist zu verwenden std::experimental::filesystem, auch (meist) bekannt als Boost.Filesystem. Damit würden Sie so etwas wie:

#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"; 
     } 
    } 
} 

anzeigen here laufen. Beachten Sie, dass die Verzeichnis-Iteratoren . und .. automatisch überspringen.

+0

Ihre Antwort ist C++ - Das OP stellt eine C-Frage – Soren

+1

Richtig, weshalb ich sagte "Wenn Sie bereit sind, nach C++ zu gehen". Da das OP sich diese Aufgabe selbst auferlegt hat, scheint C keine schwierige Anforderung zu sein, und C++ verfügt über plattformübergreifende, fast standardmäßige Einrichtungen für die Handhabung. So wie es ist, stützt es sich explizit auf Linux/POSIX-Funktionen. Meine Lösung benötigt und benötigt nicht wesentlich weniger Code, um richtig zu arbeiten und zu warten. – metal

+0

Ich habe versucht zu sehen, ob ich Ihr Beispiel zum Arbeiten bringen könnte, um die * Magie * des rekursiven Iterators zu verstehen und zu sehen, ob die Ausgabe gemäß Spezifikation formatiert werden kann - aber ich bekomme ein Problem mit Boost-Verknüpfungen wie dieser http://stackoverflow.com/questions/15634114/cant-link-program-using-boost-filesystem - ich muss sagen, ich war noch nie ein Fan von Boost, also im aufgeben, ohne in der Lage zu sein, zu machen it run – Soren