检查路径上的对象是不是是跨平台的文件或目录?

Posted

技术标签:

【中文标题】检查路径上的对象是不是是跨平台的文件或目录?【英文标题】:Check if object at a path is a file or directory cross platform?检查路径上的对象是否是跨平台的文件或目录? 【发布时间】:2020-07-12 02:39:04 【问题描述】:

您可以使用stat() 函数来检查对象是文件还是目录,例如this。我的问题是,<sys/stat.h> 不在 Windows 上,我不确定 Windows 等效或 Windows 功能是什么。这个问题是我该怎么做this,但具体是跨平台的方式。

在避免条件编译代码的同时,如何跨平台检查路径中的对象是 C 中的文件还是目录?虽然有一个almost identical question,但它没有帮助我,因为它没有答案,并且作者已被删除,因此无法维护问题。

据我了解,fopen() 是跨平台的,opendir()readdir()scandir() 等也是如此,那么为什么不简单地检查对象是否是文件或目录是跨平台的呢?如果没有办法,而条件编译的代码是唯一的办法,我在windows下怎么办?

【问题讨论】:

在标准 C 中没有办法。但条件编译是在 Windows 上完成的,而在其他操作系统上 stat() 可能会覆盖 99% 以上的(非嵌入式)使用。 @Shawn 那么它在 Windows 上是如何完成的? 打败我;我不会做很多 Windows 编程。 GetFileAttributes()GetFileType() 似乎是相关功能。 【参考方案1】:

不幸的是,在 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 系统上构建代码所需的方向前进。

希望能帮到你。

【讨论】:

什么是#include &lt;fcntl.h&gt;,为什么我需要?你能澄清一下吗? @user13783520 .. 抱歉,fcntl.h 包含其他用于 I/O 控制的功能 .. 您不需要此特定代码;修改答案以反映这一点。

以上是关于检查路径上的对象是不是是跨平台的文件或目录?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用Python以跨平台方式检查路径是绝对路径还是相对路径?

Java中如何检查文件是不是存在于目录中

跨平台桌面目录路径?

File类使用小结

检查 C++ 中是不是存在文件的最佳方法是啥? (跨平台)

如何检查文件或目录是不是为“系统”文件或目录