Как я могу отслеживать путь к файлу в рекурсивной функции? - PullRequest
0 голосов
/ 24 октября 2019

В настоящее время у меня есть функция, которая будет проходить через каталог и печатать каждый файл в каждом каталоге.

void printdir(char *dir, int depth)
{
    DIR *dp;
    struct dirent *entry;
    struct stat statbuf;
    if ((dp = opendir(dir))==NULL)
    {
        fprintf(stderr, "cannot open director: %s\n", dir);
        return;
    }
    chdir(dir);
    while((entry = readdir(dp))!=NULL)
    {
        lstat(entry->d_name, &statbuf);
        if(S_ISDIR(statbuf.st_mode))
        {
            if(strcmp(".", entry ->d_name)==0 || strcmp("..", entry->d_name) ==0)
                continue;
            printf("directory %*s%s/\n", depth, "", entry->d_name);
            printdir(entry->d_name, depth+4, path);

        }
        else printf("file %*s/%s\n", depth, "",entry->d_name);
    }
    chdir("..");
    closedir(dp);
}

Мне нужно отслеживать полное имя пути. Первоначально я делал это, имея строку malloc

char *path = malloc(sizeof(char)*500); 

, а затем я помещал исходное имя файла (полученное от пользователя) в путь. Затем я сделал путь параметром, поэтому каждый раз, когда я открывал новый каталог, я добавлял имя в путь. Единственная проблема в том, что я не знаю, когда нужно «сбросить» путь, если это имеет смысл. Поэтому, если у меня есть каталог A с каталогом B, C, D, когда я ухожу в каталог B, мне нужно сбросить путь к «./directoryA», а затем добавить каталог C. В основном, если кто-нибудь может взглянуть на мой код и посмотреть, есть лиспособ отредактировать его, чтобы я мог отслеживать имя файла, это было бы очень полезно! Спасибо!

Ответы [ 3 ]

2 голосов
/ 24 октября 2019

Стек - ваш друг, используйте его.
В приведенном ниже примере стек используется как средство для сохранения ссылки на то, где вы находитесь.
Аргумент dir для printdir теперь является копией.
Кроме того - поскольку теперь у вас есть полный путь, вам больше не нужно chdir.
Наконец, добавлено goto bail вместо возврата, чтобы освободить дескриптор каталога при ошибке.

#define _POSIX_C_SOURCE 1
#include <stdlib.h>
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <alloca.h>
#include <limits.h>

void printdir(char *dir, int depth)
{
    DIR *dp;
    struct dirent *entry;
    struct stat statbuf;
    if ((dp = opendir(dir))==NULL)
    {
        fprintf(stderr, "cannot open director: %s\n", dir);
        goto bail;
    }
    //chdir(dir);
    while((entry = readdir(dp))!=NULL)
    {            
        size_t dir_len = strlen(dir);
        size_t name_len = strlen(entry->d_name);
        char* child = (char*)alloca((dir_len + name_len + 1 /* our added '/' */ + 1 /* null termination */) * sizeof(char));
        if (child == NULL){
            fprintf(stderr,"out of stack memory");
            goto bail;
        }
        // Copy the current dir + new directory to 'child'.
        // Could use strcpy and then strcat instead
        memcpy(child,dir,dir_len);
        child[dir_len] = '/';
        memcpy(child + dir_len + 1,entry->d_name,name_len);
        child[dir_len + 1 + name_len] = '\0';

        lstat(child, &statbuf);
        if(S_ISDIR(statbuf.st_mode))
        {
            if(strcmp(".", entry ->d_name)==0 || strcmp("..", entry->d_name) ==0)
                continue;
            printf("directory %*s%s/\n", depth, "", child);
            printdir(child, depth+4);
        }
        else printf("file %*s/%s\n", depth, "",child);
    }
    //chdir("..");

bail:
    if (dp){
        closedir(dp);
    }
}

int main(int argc,char** argv){
    char* path = ".";
    printdir(path,0);
    return 0;
}
0 голосов
/ 24 октября 2019

Поскольку вы делаете DFS, вы можете просто сделать, как показано ниже, без добавления нового аргумента, как сказано в @ dash-o.

if(S_ISDIR(statbuf.st_mode))
{
    if(strcmp(".", entry ->d_name)==0 || strcmp("..", entry->d_name) ==0)
        continue;

    char newpath[500] ;     // auto variable, OR
    char path[strlen(dir) + strlen(entry->d_name) + 10) ;    // VLA
    snprintf(newpath, sizeof(newpath), "%s/%s", dir, entry->d_name)) ;

    psrintf("directory %*s%s/\n", depth, "", entry->d_name);
    printdir(newpath, depth+4);

}

Также удалите, он вам больше не нужен.

chdir(dir);
0 голосов
/ 24 октября 2019

Технически, вам не нужно использовать malloc (и не забывайте освобождать, по возвращении). Вы можете использовать локальный массив или VLA (массивы переменной длины). Предполагая, что 'fullpath' является третьим аргументом для printdir, и предполагая, что начальный вызов передаст "" в fullpath.

void printdir (char * dir, int глубина, char * fullpath)

Тогда

        if(S_ISDIR(statbuf.st_mode))
        {
            if(strcmp(".", entry ->d_name)==0 || strcmp("..", entry->d_name) ==0)
                continue;

            char newpath[500] ;     // auto variable, OR
            char path[strlen(fullpath) + strlen(entry->d_name) + 10) ;    // VLA
            snprintf(newpath, sizeof(newpath), "%s/%s", fullpath, entry->d_name)) ;

            psrintf("directory %*s%s/\n", depth, "", entry->d_name);
            printdir(entry->d_name, depth+4, newpath);

        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...