2016-11-19 1 views
-1

Je travaille sur un projet qui est censé imprimer tous les chemins de fichiers pour tous les fichiers d'un répertoire et tous ses sous-répertoires en C. Fondamentalement, cela signifie à la fin émuler l'utilitaire de recherche sous Linux.Impression récursive des chemins de fichiers de tous les fichiers d'un répertoire et de ses sous-répertoires

Je le code suivant:

void read_sub(char * sub_dir){ 
    DIR *sub_dp = opendir(sub_dir);//open a directory stream 
    struct dirent * sub_dirp;//define 
    struct stat buf;//define a file status structure 
    char temp1[]="."; 
    char temp2[]=".."; 
    char temp3[]="/"; 

    if(sub_dp!=NULL){ //Check if the directory opened successfully 

     while((sub_dirp=readdir(sub_dp))!=NULL){ //until we've read every entry one by one 

      char * temp = sub_dirp -> d_name; //get the name 

      if(strcmp(temp, temp1)!=0 && strcmp(temp, temp2)!=0){ //Ignores . and .. in the directory 

       char *temp_sub = temp3; // This is '/' 
       temp_sub = strcat(temp_sub, temp); // Adds '/' before the name of the entry 


       //now you can add the/in front of the entry's name 
       char* temp_full_path=malloc(sizeof(char)*2000); //Create a variable to hold the full path 

       //Place the passed directory at the front of the path and add the name of the file to the end 
       temp_full_path=strcpy(temp_full_path,sub_dir); 
       strcat(temp_full_path,temp_sub); 

       //try to open the file path we just created 
       DIR * subsubdp = opendir(temp_full_path); 


       //if not null, we've found a subdirectory, otherwise it's a file 
       if(subsubdp!=NULL){ 
         //close the stream because it'll be reopened in the recursive call. 
        closedir(subsubdp); 
        read_sub(temp_full_path);//call the recursive function call. 
       }else{ 
        printf("%s\n",temp_full_path); 
       } 
      } 
     }//end of while loop 
     closedir(sub_dp);//close the stream 
    }else{ 
     printf("cannot open directory\n"); 
     exit(2); 
    } 
} 

Je suis en cela en passant directement ce "testdir", qui est un répertoire avec la structure suivante:

testdir/ 
|-- dir1 
| |-- dir2 
| | |-- test5 
| | `-- test6 
| |-- test3 
| `-- test4 
|-- dir3 
| |-- test7 
| `-- test8 
|-- test1 
`-- test2 

Ainsi, il devrait sortie quelque chose comme:

testdir/dir1/dir2/test5 
testdir/dir1/dir2/test6 
testdir/dir1/test3 
testdir/dir1/test4 

Et ainsi de suite. Cependant, le résultat réel est:

testdir/dir1/dir2/test6 
testdir/dir1/dir2/test6test5 
testdir/dir1/dir2test3 
testdir/dir1/dir2test3test4 
testdir/dir1test1 
testdir/dir1test1dir3 
testdir/dir1test1dir3test2 

Il semble donc qu'il ne peut pas être correctement compensation le chemin complet du fichier quand il est en cours d'exécution est ma conjecture? En outre, il ne semble pas réellement entrer dir3 pour imprimer test7 et test8. Que fais-je incorrectement? Merci.

+0

La première chose qui semble mauvais, en utilisant 'strcat()' –

+0

méthode Utilisez DFS ou BFS pour imprimer des chemins de tous les fichiers et répertoires d'un annuaire. –

+0

Comme toujours, la meilleure chose à faire serait d'utiliser la fonction '* at()' de la famille de fichiers/répertoires dans POSIX. – EOF

Répondre

1

Vous n'allouez pas suffisamment d'espace pour les chaînes cibles. Vous avez besoin d'au moins PATH_MAX octets.

Essayez

char temp1[PATH_MAX] = "."; 
char temp2[PATH_MAX] = ".."; 
char temp3[PATH_MAX] = "/"; 

Comme il était, le compilateur n'allouer assez d'espace pour contenir la chaîne d'initialisation, (2, 3, 2) respectivement. Votre programme présentait donc un comportement indéfini. Je recommanderais snprintf() au lieu de strcat() car c'est direct et pas aussi cher. Avec strcat() chaque fois que vous l'appelez, il recherchera la fin actuelle de la chaîne cible en itérant jusqu'à ce qu'il trouve la fin '\0'.

Essayez également d'utiliser le plus petit nombre de niveaux d'indentation car le code devient rapidement très illisible.

0

Vous pouvez utiliser S_ISDIR pour tester le répertoire. malloc doit être nettoyé avec free pour éviter les fuites de mémoire. Il peut être trop compliqué d'implémenter malloc/free dans une fonction récursive, il est donc préférable de déclarer simplement un tampon temporaire path[4096]. Cela fonctionne tant que le nom du chemin n'est pas trop long. Si le chemin est trop long, l'option la plus sûre consiste à imprimer une erreur et à ne pas continuer.

Pour "." et ".." vous pouvez déclarer

const char *temp1 = "."; 
const char *temp2 = ".."; 

De cette façon, vous évitez d'écrire accidentellement temp1 et temp2.

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <dirent.h> 
#include <sys/stat.h> 

void read_sub(char *subdir) 
{ 
    DIR *dirp = opendir(subdir); 
    if (!dirp) 
     return; 

    struct dirent *dentry; 
    while ((dentry = readdir(dirp)) != 0) 
    { 
     if (strcmp(dentry->d_name, ".") == 0 || strcmp(dentry->d_name, "..") == 0) 
      continue; 

     printf("%s/", subdir); 

     char path[4096]; 
     int len = strlen(subdir) + 1 + strlen(dentry->d_name) + 1; 
     if (len >= sizeof(path)) 
     { 
      printf("path is too long...\n"); 
      break; 
     } 
     sprintf(path, "%s/%s", subdir, dentry->d_name); 

     struct stat st; 
     stat(path, &st); 
     if (S_ISDIR(st.st_mode)) 
     { 
      printf("%s\n", dentry->d_name); 
      read_sub(path); 
     } 
     else 
     { 
      printf("%s\n",dentry->d_name); 
     } 
    } 

    closedir(dirp); 
} 

Vous pouvez aussi utiliser le tableau de longueur variable pour path

int len = strlen(subdir) + 1 + strlen(dentry->d_name) + 1; 
char path[len]; 
sprintf(path, "%s/%s", subdir, dentry->d_name);