Проверить, является ли объект по пути кроссплатформенным файлом или каталогом? - PullRequest
2 голосов
/ 12 июля 2020

Вы можете использовать функцию stat(), чтобы проверить, является ли объект файлом или каталогом, например this . Моя проблема в том, что <sys/stat.h> отсутствует в Windows, и я не уверен, что такое Windows эквивалент или Windows функция. Этот вопрос заключается в том, как мне сделать это , но конкретно кроссплатформенным образом.

Избегая условно скомпилированного кода, как я могу кросс-платформенный проверить, является ли объект на пути файлом или каталог в C? Хотя есть почти идентичный вопрос , он не может мне помочь, поскольку на него нет ответа, а автор удален, поэтому вопрос не может быть сохранен.

Насколько я понимаю, fopen() кроссплатформенный, и так и opendir(), readdir(), scandir() et c, так почему бы просто не проверить, является ли объект файлом или каталогом, перекрестной платформой? Если способа нет, а условно скомпилированный код - единственный способ, как мне это сделать в Windows?

1 Ответ

0 голосов
/ 12 июля 2020

К сожалению, в C нет простого, переносимого или прямого способа сделать это.

Для этого вот немного кода C, который я преобразовал из некоторого кода C ++, который я написал для кроссплатформенная библиотека, которую можно использовать для проверки существования файла или каталога:

#include <sys/stat.h>
#include <sys/types.h>
#if defined(OS_WIN)
    #include <windows.h>
#else
    #include <dirent.h> // for *Nix directory access
    #include <unistd.h>
#endif

bool file_exists(const char* file)
{
    if (file == NULL) { return false; }
    #if defined(OS_WIN)
        #if defined(WIN_API)
            // if you want the WinAPI, versus CRT
            if (strnlen(file, MAX_PATH+1) > MAX_PATH) {
                // ... throw error here or ...
                return false;
            }
            DWORD res = GetFileAttributesA(file);
            return (res != INVALID_FILE_ATTRIBUTES &&
                !(res & FILE_ATTRIBUTE_DIRECTORY));
        #else
            // Use Win CRT
            struct stat fi;
            if (_stat(file, &fi) == 0) {
                #if defined(S_ISSOCK)
                    // sockets come back as a 'file' on some systems
                    // so make sure it's not a socket or directory
                    // (in other words, make sure it's an actual file)
                    return !(S_ISDIR(fi.st_mode)) &&
                        !(S_ISSOCK(fi.st_mode));
                #else
                    return !(S_ISDIR(fi.st_mode));
                #endif
            }
            return false;
        #endif
    #else
        struct stat fi;
        if (stat(file, &fi) == 0) {
            #if defined(S_ISSOCK)
                return !(S_ISDIR(fi.st_mode)) &&
                    !(S_ISSOCK(fi.st_mode));
            #else
                return !(S_ISDIR(fi.st_mode));
            #endif
        }
        return false;
    #endif
}

bool dir_exists(const char* folder)
{
    if (folder == NULL) { return false; }
    #if defined(OS_WIN)
        #if defined(WIN_API)
            // if you want the WinAPI, versus CRT
            if (strnlen(folder, MAX_PATH+1) > MAX_PATH) {
                // ... throw error here or ...
                return false;
            }
            DWORD res = GetFileAttributesA(folder);
            return (res != INVALID_FILE_ATTRIBUTES &&
                (res & FILE_ATTRIBUTE_DIRECTORY));
        #else
            struct stat fi;
            if (_stat(folder, &fi) == 0) {
                return (S_ISDIR(fi.st_mode));
            }
            return false;    
        #endif
    #else
        struct stat fi;
        if (stat(folder, &fi) == 0) {
            return (S_ISDIR(fi.st_mode));
        }
        return false;
    #endif
}

Чтобы создать его для Windows, просто определите OS_WIN для этой сборки; Кроме того, если вы хотите использовать полный WinAPI, а не использовать Windows CRT, вы можете определить WIN_API.

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

bool is_file(const char* path)
{
    return file_exists(path) && !dir_exists(path);
}

bool is_dir(const char* path)
{
    return dir_exists(path) && !file_exists(path);
}

Очевидно, вы можете изменить код в соответствии с вашими потребностями, но это должно направить вас в том направлении, в котором вам нужно создавать свой код в системах Windows / macOS / * nix.

Надеюсь, это поможет.

...