天天看点

4.3 文件类型判断宏与文件类型常量

文件类型信息包含在stat结构的st_mode成员中,大多数系统都在文件<sys/stat.h>中定义了对应的类型字和类型判断宏。

一、判断文件类型方法有两种:

(1)用文件类型判断宏:例如S_ISREG(buf.st_mode)

(2)先用文件类型屏蔽字(S_IFMT)与buf.st_mode进行“按位与”运算,然后再与对应的类型字相比较。例如:(buf.st_mode & S_IFMT) == S_IFREG。

二、相关宏的定义

(1)文件:<bits/stat.h>

#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.  */

/* POSIX.1b objects.  Note that these macros always evaluate to zero.  But
   they do it by enforcing the correct use of the macros.  */
#define __S_TYPEISMQ(buf)  ((buf)->st_mode - (buf)->st_mode)
#define __S_TYPEISSEM(buf) ((buf)->st_mode - (buf)->st_mode)
#define __S_TYPEISSHM(buf) ((buf)->st_mode - (buf)->st_mode)
           

(2)文件:sys/stat.h

#include <bits/stat.h>

#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
# 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

/* 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

/* These are from POSIX.1b.  If the objects are not implemented using separate
   distinct file types, the macros always will evaluate to zero.  Unlike the
   other S_* macros the following three take a pointer to a `struct stat'
   object as the argument.  */
#ifdef	__USE_POSIX199309
# define S_TYPEISMQ(buf) __S_TYPEISMQ(buf)
# define S_TYPEISSEM(buf) __S_TYPEISSEM(buf)
# define S_TYPEISSHM(buf) __S_TYPEISSHM(buf)
#endif
           

三、将相关类型判断宏与类型判断字列表如下

文件类型 类型判断宏 类型判断字 判断字赋值(八进制)
类型屏蔽字 S_IFMT 0170000
FIFO S_ISFIFO(st_mode) S_IFIFO 0010000
字符特殊文件 S_ISCHR(st_mode) S_IFCHR 0020000
目录文件 S_ISDIR(st_mode) S_IFDIR 0040000
块特殊文件 S_ISBLK(st_mode) S_IFBLK 0060000
普通文件 S_ISREG(st_mode) S_IFREG 0100000
符号链接 S_ISLNK(st_mode) S_IFLNK 0120000
套接字 S_ISSOCK(st_mode) S_IFSOCK 0140000
消息队列 S_TYPEISMQ(stat)
信号量 S_TYPEISSEM(stat)
共享存储对象 S_TYPEISSHM(stat)

说明:

类型判断宏参数不都是一样的:

基本文件类型参数为st_mode,它是一个stat结构的st_mode成员;而进程间通信类型参数为stat结构

四、stat.st_mode分析

从上表个判断字赋值看以看出,stat.st_mode的bit12~bit15位包含着文件类型信息。文件类型屏蔽字S_IFMT其八进制值为0170000,转换为二进制为:1 111 000 000 000 000B,通过文件类型屏蔽字与stat.st_mode进行与运算可以提取出文件类型信息(stat.st_mode & S_IFMT)。

五、实例分析

实例 x.4.3.1.c

#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>

int shw_f_type(char *pathname);

int main(int argc, char *argv[])
{
    int     i;

    for (i = 1; i < argc; i++) {
        printf("%s:", argv[i]);
        shw_f_type(argv[i]);
        printf("\n");
    }

    exit(0);

}

int shw_f_type(char *pathname)
{
    
    struct stat buf;

    if (lstat(pathname, &buf) == -1) {    /*取文件属性数据*/
        printf("lstat error");
        return 1;
    }

    if (S_ISREG(buf.st_mode))             /*普通文件*/
        printf("regular");
    else if (S_ISDIR(buf.st_mode))        /*目录文件*/
        printf("directory");
    else if (S_ISCHR(buf.st_mode))        /*字符特殊文件*/
        printf("character special");
    else if (S_ISBLK(buf.st_mode))        /*块特殊文件*/
        printf("block special");
    else if (S_ISFIFO(buf.st_mode))       /*管道或FIFO*/
        printf("fifo");
    else if (S_ISLNK(buf.st_mode))        /*符号链接*/
        printf("symblic link");
    else if (S_ISSOCK(buf.st_mode))       /*套接子*/
        printf("socket");
    else                                  /*未知类型*/
        printf("** unknown mode **");

    return 0;

}
           

编译与执行:

[[email protected] unixc]# cc x.4.3.1.c

[[email protected] unixc]# ./a.out /etc/passwd /etc /dev/log /dev/tty /dev/sda

/etc/passwd:regular

/etc:directory

/dev/log:socket

/dev/tty:character special

/dev/sda:block special

[[email protected] unixc]#

继续阅读