opendir () с ошибкой в ​​имени с пробелом, работает на Linux - PullRequest
0 голосов
/ 25 октября 2019

Моя программа исследует текущий каталог и все подкаталоги, чтобы напечатать все имена файлов. Однако он вызывает ошибку сегментации, когда в каталоге есть пробел в имени. Это происходит только в Linux - Windows работает нормально.

Имя хранится в dirent.d_name, что char[256]. Я попытался использовать его, преобразовав его в c-строку, используя c_str(), я пытался жестко кодировать имя каталога в коде, я пытался избежать пробела (хотя я не думаю, что я делаю этоправильно).

int main()
{
    struct dirent *direntry;
    dir = opendir( "hello\ world" );
    print_dir_rec( dir, direntry );
    return 0;
}

void print_dir_rec( DIR *dir, struct dirent *direntry )
{
    while( direntry = readdir(dir) )
    {
        switch( direntry->d_type )
        {
            case DT_DIR:
                DIR *sub_dir = opendir( direntry->d_name );
                print_dir_rec( sub_dir , direntry );
                break;
        }
    }
    return;
}

1 Ответ

1 голос
/ 25 октября 2019

Вы сталкиваетесь с проблемами, передавая указатель DIR* и указатель struct dirent* в качестве параметров вместо простого формирования и передачи следующего пути к открытию. Вы хотите обрабатывать открытие каталога внутри самой рекурсивной функции, а не как один указатель, переданный из main(), например,

void print_dir_rec(const char *name)
{
    DIR *dir;
    struct dirent *entry;

    if (!(dir = opendir(name)))
        return;

    while ((entry = readdir(dir)) != NULL) {
        if (entry->d_type == DT_DIR) {
            char path[1024];
            if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
                continue;
            snprintf(path, sizeof(path), "%s/%s", name, entry->d_name);
            printf("[%s]\n", entry->d_name);
            print_dir_rec(path);
        }
    }
    closedir(dir);
}

( примечание: вы можете настроить числосимволов, предоставленных для path при необходимости или с помощью макроса PATH_MAX)

Таким образом, не существует единственного указателя, который будет повторно использоваться в каждом рекурсивном вызове, вызывающем проблемы. Короткий пример, в котором перечислены все каталоги под текущим, может быть:

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

void print_dir_rec(const char *name)
{
    DIR *dir;
    struct dirent *entry;

    if (!(dir = opendir(name)))
        return;

    while ((entry = readdir(dir)) != NULL) {
        if (entry->d_type == DT_DIR) {
            char path[1024];
            if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
                continue;
            snprintf(path, sizeof(path), "%s/%s", name, entry->d_name);
            printf("[%s]\n", entry->d_name);
            print_dir_rec(path);
        }
    }
    closedir(dir);
}

int main(void) {
    print_dir_rec(".");
    return 0;
}

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

Дайте мне знать, если у вас есть дополнительные вопросы.

...