Unix编程之文件类型检测

坚持 成长 每日一篇

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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值