2015-08-02 1 views
3

Я делаю рекурсивную прогулку по каталогам, чтобы вносить изменения в файлы. Моя функция файла изменений требует полного пути к файлу, чтобы иметь возможность делать вещи. Однако то, что моя программа делает прямо сейчас, это просто получить имя текущего файла или папки, но не полный путь.Получение полного пути к файлу во время рекурсивного перемещения файла C

Мой подход заключается в том, что я сделал бы строку и сохраняю приложенные имена до тех пор, пока не получу полный путь. Однако, поскольку я делаю рекурсию, у меня возникают проблемы с передачей строки, чтобы добавить к ней больше строк.

Это мой код:

#include <stdio.h> 
#include <stdlib.h> 
#include <regex.h> 
#include <string.h> 
#include <dirent.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <errno.h> 

void recursiveWalk(const char *pathName, char *fullPath, int level) { 
    DIR *dir; 
    struct dirent *entry; 

    if (!(dir = opendir(pathName))) { 
     fprintf(stderr, "Could not open directory\n"); 
     return; 
    } 

    if (!(entry = readdir(dir))) { 
     fprintf(stderr, "Could not read directory\n"); 
     return; 
    } 

    do { 
     if (entry->d_type == DT_DIR) { // found subdirectory 
     char path[1024]; 

     int len = snprintf(path, sizeof(path)-1, "%s/%s", pathName, entry->d_name); // get depth 
     path[len] = 0; 

     // skip hidden paths 
     if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { 
      continue; 
     } 

     fprintf(stdout, "%*s[%s]\n", level*2, "", entry->d_name); 

     // Append fullPath to entry->d_name here 

     recursiveWalk(path, fullPath, level + 1); 
     } 
     else { // files 
     fprintf(stdout, "%*s- %s\n", level*2, "", entry->d_name); 

     //changeFile(fullPath); 
     } 
    } while (entry = readdir(dir)); 

    closedir(dir); 
} 

int main(int argn, char *argv[]) { 
    int level = 0; 
    recursiveWalk(".", "", level); 

    return 0; 
} 
+0

'recursiveWalk (шаблон, замена, путь, FULLPATH , level + 1); 'зачем давать здесь столько аргументов? – ameyCU

+0

'char path [1024];'? Опасность, Уилл Робинсон? – paulsm4

+0

Не изменяйте имя переданного пути; сделайте копию его, добавьте в копию, оставьте исходный текст неповрежденным. –

ответ

1

В коде есть множество проблем.

  • вы никогда не использовали ни изменить fullPath в recursiveWalk
  • ваши форматы странно: вы используете level*2 ограничить количество напечатанных символов с пустой строкой
  • вы вычислить фактический путь только тогда, когда у вас есть нашел каталог, в то время как вы говорите, что вам нужно его для изменения файла.
  • добавить path[len] = 0 после snprintf когда snprintf гарантирует, но буфер нуля

Но кроме того, вы правильно пройти путь к анализируемой директории добавить в пути, пройденном в первоначальном вызове, но в pathName переменной и вычисляется как path.

Так можно исправить для вашего кода будет:

  • исправить форматы для Printf
  • удалить неиспользуемую fullPath параметр из recursiveWalk
  • ВСЕГДА вычислить path и использовать его в файле филиала
  • комментировать вне path[len] = '\0'
  • Я также заменить while (entry = readdir(dir)); с while ((entry = readdir(dir))); недвусмысленном сказать компилятору, что я хочу, чтобы установить запись, а затем проверить его значение - и убрать предупреждение

Возможный код:

#include <stdio.h> 
#include <stdlib.h> 
#include <regex.h> 
#include <string.h> 
#include <dirent.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <errno.h> 

void recursiveWalk(const char *pathName, int level) { 
    DIR *dir; 
    struct dirent *entry; 

    if (!(dir = opendir(pathName))) { 
     fprintf(stderr, "Could not open directory\n"); 
     return; 
    } 

    if (!(entry = readdir(dir))) { 
     fprintf(stderr, "Could not read directory\n"); 
     return; 
    } 

    do { 
     char path[1024]; 
     int len = snprintf(path, sizeof(path)-1, "%s/%s", pathName, entry->d_name); // get depth 
     // path[len] = 0; 
     if (entry->d_type == DT_DIR) { // found subdirectory 


     // skip hidden paths 
     if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { 
      continue; 
     } 

     fprintf(stdout, "%s [%s] (%d)\n", pathName, entry->d_name, level); 

     // Append fullPath to entry->d_name here 

     recursiveWalk(path, level + 1); 
     } 
     else { // files 
     fprintf(stdout, "%s (%d)\n", path, level); 

     //changeFile(fullPath); 
     } 
    } while ((entry = readdir(dir))); 

    closedir(dir); 
} 

int main(int argn, char *argv[]) { 
    int level = 0; 
    recursiveWalk(".", level); 

    return 0; 
} 
1

Рекурсия является лаконичным способом выразить вещи (особенно ходьба каталоги), но на самом деле вы обычно должны избегать его на практике. Если дерево каталогов достаточно глубокое, это приведет к сбою вашего программного обеспечения.

Использование очереди исключает необходимость рекурсии и, как правило, является эффективным способом перемещения.

я в том числе код, я использую для обработки дерева каталогов в виде project ...

static int on_dir(const char* const dir, struct duplicate** dp) { 
    bool r = opts.recurse; 

    DIR* d = opendir(dir); 

    if (!d) 
    return - 1; 

    struct dirent* de; 

    while ((de = readdir(d))) { 

    struct stat s; 

    size_t bs = strlen(dir) + strlen(de->d_name) + 2; 
    char b[bs]; 

    const char* const a = strjoin(b, dir, de->d_name, '/'); 

    if (lstat(a, &s)) { 

     print_error("unable to stat %s", d); 
     continue; 
    } 

    if (S_ISREG(s.st_mode)) 
     if (on_file(a, &s, dp)) 
     print_error("unable to process file %s/%s", dir, de->d_name); 
    } 

    if (!r) { 

    if (closedir(d)) 
     on_fatal("unable to close directory %s", dir); 

    return 0; 
    } 

    rewinddir(d); 

    while ((de = readdir(d))) { 

    struct stat ds; 

    size_t bs = strlen(dir) + strlen(de->d_name) + 2; 
    char b[bs]; 

    const char* const d = strjoin(b, dir, de->d_name, '/'); 

    if (lstat(d, &ds)) { 

     print_error("unable to stat %s", d); 
     continue; 
    } 

    if (S_ISDIR(ds.st_mode)) { 

     const char* const dot = "."; 
     const char* const dotdot = ".."; 

     if (!strcmp(dot, de->d_name) || !strcmp(dotdot, de->d_name)) 
     continue; 

     struct path* p = path_create(strcpy(fmalloc(bs), d)); 

     queue_add(&paths, &p->queue); 
    } 
    } 

    if (closedir(d)) 
    print_error("unable to close directory %s", dir); 

    return 0; 
} 

и код strjoin

static inline char* strjoin(char* restrict const d, const char* restrict const a, const char* restrict const b, const char c) { 
    size_t na = strlen(a); 
    size_t nb = strlen(b); 

    memcpy(d, a, na); 
    d[na] = c; 
    memcpy(d + na + 1, b, nb); 

    d[na + nb + 1] = '\0'; 

    return d; 
} 

Я надеюсь, что это помогает. Не стесняйтесь использовать любой код, который вы найдете в репозитории git.

Смежные вопросы