Unix编程之文件类型检测

来源:互联网 发布:电子线路画图软件 编辑:程序博客网 时间:2024/05/29 21:30

坚持 成长 每日一篇

stat结构体介绍

在unix系统中我们可以通过了解stat 结构体的成员了解文件的所有属性。结构体的定义可能随实现有所不同,但其基本形式是:下面是mac下的stat格式

struct stat {    dev_t       st_dev;     /* 拥有该文件的设备ID[XSI] ID of device containing file */    ino_t       st_ino;     /* 文件结点号[XSI] File serial number */    mode_t      st_mode;    /* 文件的类型 Mode of file (see below) */    nlink_t     st_nlink;   /* 硬连接数 Number of hard links */    uid_t       st_uid;     /* 文件用户标识 User ID of the file */    gid_t       st_gid;     /* 文件用户组标识 Group ID of the file */    dev_t       st_rdev;    /* 文件所表示的特殊设备文件的设备标识 Device ID for sepecial files */#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)    struct  timespec st_atimespec;  /* time of last access */    struct  timespec st_mtimespec;  /* time of last data modification */    struct  timespec st_ctimespec;  /* time of last status change */#else    time_t      st_atime;   /* 最后的访问时间 Time of last access */    long        st_atimensec;   /* nsec of last access */    time_t      st_mtime;   /* 最后修改时间 Last data modification time */    long        st_mtimensec;   /* last data modification nsec */    time_t      st_ctime;   /* 最后状态改变时间 Time of last status change */    long        st_ctimensec;   /* nsec of last status change */#endif    off_t       st_size;    /* 总大小,字节为单位 file size, in bytes */    blkcnt_t    st_blocks;  /* 允许分配给文件的块的数量,512字节为单元 blocks allocated for file */    blksize_t   st_blksize; /* 文件系统的块大小 optimal blocksize for I/O */    __uint32_t  st_flags;   /* 用户自定义文件描述符给该文件 user defined flags for file */    __uint32_t  st_gen;     /* file generation number */    __int32_t   st_lspare;  /* RESERVED: DO NOT USE! */    __int64_t   st_qspare[2];   /* RESERVED: DO NOT USE! */}     

文件类型

Unix中大多数的文件类型是普通文件或目录。下面是Unix文件类型的介绍

  1. 普通文件:包含了某种形式的数据。对于Unix内核而言,不管是文本还是二进制数据都没有区别。对于普通文件内容的解释是由处理该文件的应用程序进行的。
  2. 目录文件:包含其他文件的名字以及执行这些文件有关信息的指针。对目录文件有读权限的任一进程都可以读该目录内容,但只有内核可以直接写目录。进程需要通过一些函数才能修改目录。
  3. 特殊文件:提供对设备(如磁盘)带缓冲的访问,每次访问以固定长度为单位进行。
  4. 字符特殊文件:提供对设备不带缓冲的访问,每次访问长度可变。(FreeBSD所有设备都是通过字符特殊文件访问,没有特殊文件)
  5. FIFO:用于进程间通信,也叫管道。
  6. 套接字:用于进程间的网络通信。
  7. 符号连接:该文件会指向另一个文件
    上面的7种文件类型包含在stat结构体的st_mode成员中。通过使用下面宏的参数可以确定文件类型。
    例如判断文件是否是目录文件类型:
 #define S_ISDIR(mode) (((mode)&S_IFMT)== S_IFDIR);

各种类型文件对应的宏如下
S_ISREG() 普通文件
S_ISDIR() 目录文件
S_ISCHR() 字符特殊文件
S_ISBLK() 块特殊文件
S_ISFIFO() 管道活着FIFO
S_ISLNK() 符号连接
S_ISSOCK() 套接字

POSIX.1允许实现将进程通信对象当作文件,但是坚持宏参数不是stat的st_mode而是stat的指针

S_TYPEISMQ(buf):消息队列S_TYPEISSEM(buf):信号量S_TYPEISSHM(buf):共享存储对象

函数stat,fstat,fstatat,lstat获取文件的结构体stat

我们可以通过下面的四个函数获取文件的stat。下面是从mac上截取的四个函数定义

#include <sys/stat.h>int fstat(int fd, struct stat *buf) __DARWIN_INODE64(fstat);int lstat(const char *pathname, struct stat *buf) __DARWIN_INODE64(lstat);int stat(const char *pathname, struct stat *buf) __DARWIN_INODE64(stat);int fstatat(int fd, const char *pathname, struct stat *buf, int flag);

fstat 根据打开的文件描述符fd上的文件返回stat;
lstat 返回符号连接的有关信息,而不是符号连接引用的文件信息。
stat 返回此命名文件有关的信息,如果是符号连接返回连接引用的文件信息。
fstatat 如果flag设置为:AT_SYMLINK_NOFOLLOW,则类似lstat。否则默认类似于stat
fd参数为AT_FDCWD 表示pathname支持相对路径。如果pathname是绝对路径fd传什么都无所谓

测试源码

#include <stdio.h>#include <sys/stat.h>#include <time.h>//时间转换,参数word修饰这是什么时间void printfTime(long time,char word[]){    static char str_time[100];    struct tm *local_time = NULL;    time_t utc_time;    utc_time = time;    local_time = localtime(&utc_time);    strftime(str_time, sizeof(str_time), "%Y-%m-%d,%H:%M:%S", local_time);    printf("%s:%s\n",word,str_time);}int main(int argc, const char * argv[]){    int i;    struct stat buf;    char *ptr;    //遍历判断文件的类型    for (i = 1; i<argc; i++) {        printf("%s: ",argv[i]);        if (lstat(argv[i], &buf)<0) {            printf("error:");            perror("lstat error");            continue;        }        //通过检查stat结构体buf的st_mode来检查文件类型        if (S_ISREG(buf.st_mode)) {            ptr = "regular";//普通文件        }else if(S_ISDIR(buf.st_mode)){            ptr = "S_ISDIR";//目录文件        }else if(S_ISCHR(buf.st_mode)){            ptr = "S_ISCHR";//字符特殊文件        }else if(S_ISBLK(buf.st_mode)){            ptr = "S_ISBLK";//块特殊文件        }else if(S_ISFIFO(buf.st_mode)){            ptr = "S_ISFIFO";//管道或FIFO        }else if(S_ISLNK(buf.st_mode)){            ptr = "S_ISLNK";//符号链接        }else if(S_ISSOCK(buf.st_mode)){            ptr = "S_ISSOCK";//套接字        }else{            ptr = "** _unknow mode **";        }        printf(" %s\n",ptr);        printf("time = %ld\n",buf.st_atime);        printfTime(buf.st_atime,"访问时间");        printfTime(buf.st_ctime,"修改时间");        printfTime(buf.st_birthtime,"创建时间");        printf("DeviceID = %d\n",buf.st_dev);        printf("UserID = %d\n",buf.st_uid);        printf("文件大小:%lld字节\n",buf.st_size);        //**可以判断该Stat是不是信号量        if(S_TYPEISMQ(buf)){printf("是一个消息队列\n");}else printf("NO Queue\n");        if(S_TYPEISSEM(buf)){printf("是一个信号量\n");}else printf("NO SEM\n");        if(S_TYPEISSHM(buf)){printf("是一个共享存储对象\n");}else printf("NO SHM\n");    }    return 0;}
0 0
原创粉丝点击