【C/C++文件处理系列】通过struct stat中的st_mode判断文件类型

linux系统文件类型有七种,即:普通文件、目录文件、字符设备、块设备、管道文件、链接文件和套接字文件。

通过 man 2 stat 可获取到 其中 st_mode 可以用来判别服务的类型。原文如下:

The following POSIX macros are defined to check the file type using the st_mode field:

           S_ISREG(m)  is it a regular file?

           S_ISDIR(m)  directory?

           S_ISCHR(m)  character device?

           S_ISBLK(m)  block device?

           S_ISFIFO(m) FIFO (named pipe)?

           S_ISLNK(m)  symbolic link? (Not in POSIX.1-1996.)

           S_ISSOCK(m) socket? (Not in POSIX.1-1996.)

其中st_mode字段涉及到文件类型的判断如下:

       The following flags are defined for the st_mode field:

           S_IFMT     0170000   bit mask for the file type bit fields
           S_IFSOCK   0140000   socket
           S_IFLNK    0120000   symbolic link
           S_IFREG    0100000   regular file
           S_IFBLK    0060000   block device
           S_IFDIR    0040000   directory
           S_IFCHR    0020000   character device
           S_IFIFO    0010000   FIFO

综上,即通过 macros宏命令  S_ISREG(m) 可以判断是否为普通文件, S_ISDIR(m)  判断是否为路径……

在  sys/stat.h 文件中可以找到macros的定义,如下

/* Test macros for file types.  */

#define __S_ISTYPE(mode, mask)  (((mode) & __S_IFMT) == (mask))

#define S_ISDIR(mode)    __S_ISTYPE((mode), __S_IFDIR)
#define S_ISCHR(mode)    __S_ISTYPE((mode), __S_IFCHR)
#define S_ISBLK(mode)    __S_ISTYPE((mode), __S_IFBLK)
#define S_ISREG(mode)    __S_ISTYPE((mode), __S_IFREG)
#ifdef __S_IFIFO
# define S_ISFIFO(mode)  __S_ISTYPE((mode), __S_IFIFO)
#endif
#ifdef __S_IFLNK
# define S_ISLNK(mode)   __S_ISTYPE((mode), __S_IFLNK)
#endif

#if defined __USE_BSD && !defined __S_IFLNK
# define S_ISLNK(mode)  0
#endif
#if (defined __USE_BSD || defined __USE_UNIX98 || defined __USE_XOPEN2K) \
    && defined __S_IFSOCK
# define S_ISSOCK(mode) __S_ISTYPE((mode), __S_IFSOCK)
#elif defined __USE_XOPEN2K
# define S_ISSOCK(mode) 0
#endif

预先定义一个 函数 __S_ISTYPE(mode, mask)  (((mode) & __S_IFMT) == (mask)),通过传入 mode 与 __S_IFMT 做 按位与 后的结果 与 mask 比较,如果与传入的mask一样,则判断为该类型文件。

首先,在 sys/stat.h 中搜索 __S_IFMT 来查找定义部分,如下文

#include 

#if defined __USE_BSD || defined __USE_MISC || defined __USE_XOPEN
# define S_IFMT         __S_IFMT
# define S_IFDIR        __S_IFDIR
# define S_IFCHR        __S_IFCHR
# define S_IFBLK        __S_IFBLK
# define S_IFREG        __S_IFREG
# define S_IFDIR        __S_IFDIR
# define S_IFCHR        __S_IFCHR
# define S_IFBLK        __S_IFBLK
# define S_IFREG        __S_IFREG
# ifdef __S_IFIFO
#  define S_IFIFO       __S_IFIFO
# endif
# ifdef __S_IFLNK
#  define S_IFLNK       __S_IFLNK
# endif
# if (defined __USE_BSD || defined __USE_MISC || defined __USE_UNIX98) \
     && defined __S_IFSOCK
#  define S_IFSOCK      __S_IFSOCK
# endif
#endif

即可以在 #include 中 找到相关定义,打开bits/stat.h 文件,继续搜索__S_IFMT  ,得到如下内容:

/* Encoding of the file mode.  */

#define __S_IFMT        0170000 /* These bits determine file type.  */

/* File types.  */
#define __S_IFDIR       0040000 /* Directory.  */
#define __S_IFCHR       0020000 /* Character device.  */
#define __S_IFBLK       0060000 /* Block device.  */
#define __S_IFREG       0100000 /* Regular file.  */
#define __S_IFIFO       0010000 /* FIFO.  */
#define __S_IFLNK       0120000 /* Symbolic link.  */
#define __S_IFSOCK      0140000 /* Socket.  */

上文先定义了 文件类型的掩码 __S_IFMT  为 0170000  八进制的。然后针对 七种文件类型定义了不同的编码。

###########

通过阅读以上各个定义,回过头重新看 宏命令的定义(只罗列了部分):

#define __S_ISTYPE(mode, mask)  (((mode) & __S_IFMT) == (mask))

#define S_ISDIR(mode)    __S_ISTYPE((mode), __S_IFDIR)
#define S_ISCHR(mode)    __S_ISTYPE((mode), __S_IFCHR)

1、即判别一个文件是否为目录时,可以调用S_ISDIR(mode),宏命令,其函数原型为 调用   __S_ISTYPE((mode), __S_IFDIR)

2、__S_IFDIR 的编码为 0040000 ,八进制,即 传参后    __S_ISTYPE((mode), 0040000 )

3、参考__S_ISTYPE 的原型 :#define __S_ISTYPE(mode, mask)  (((mode) & __S_IFMT) == (mask)),其中__S_IFMT的编码为0170000  ,八进制。

    传参后如下:#define   __S_ISTYPE(mode, __S_IFDIR )    (((mode) & __S_IFMT) == (__S_IFDIR ))

                  即 : #define   __S_ISTYPE(mode, 0040000 )    (((mode) & 0170000  ) == (0040000 ))

4、mode 参数为 struct stat 中 st_mode的值, 可以通过stat() 函数获取。

    struct stat mystat;
    stat("/data/natpan/tmp/LTars/l_file",&mystat)

 即  mystat.st_mode  为传入  __S_ISTYPE 函数中的 mode。

5、 通过  mystat.st_mode 与掩码 __S_IFMT 按位与,结果与 __S_IFDIR 比较,相同则为 目录。

6、其余文件类型 判断方法类似。

方便按位运算,打印了各个类型定义编码的 二进制格式
 

S_IFMT   :1111000000000000 Octal: 0170000 ## bit mask for the file type bit fields
S_IFSOCK :1100000000000000 Octal: 0140000  socker
S_IFLNK  :1010000000000000 Octal: 0120000  symbolic link
S_IFREG  :1000000000000000 Octal: 0100000  regular file
S_IFBLK  :0110000000000000 Octal: 0060000  block device
S_IFDIR  :0100000000000000 Octal: 0040000 directory
S_IFCHR  :0010000000000000 Octal: 0020000  character device
S_IFIFO  :0001000000000000 Octal: 0010000  FIFO

 

你可能感兴趣的:(【C/C++文件处理系列】)