Linux系统中获取文件属性信息stat相关函数 | 获取系统时间的相关函数 | 目录操作的相关函数

前言

继前文linux系统中文件IO常用的函数(总结)感兴趣可以了解一下。

一、文件IO常用函数练习

继前文,我们来做一个综合小练习,使用文件IO实现文件的拷贝

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#define PRINT_ERR(msg) \
    do                 \
    {                  \
        printf("%s %s %d\n",__FILE__,__func__,__LINE__);      \
        perror(msg);   \
        return -1;     \
    } while (0)

int main(int argc, const char* argv[])
{
    int sfd,dfd,ret;
    char buf[128]={0};
    //1.判断传参是否正确./a.out srcfile destfile
    if(argc!=3)
    {
        fprintf(stderr, "input error,try again\n");
        fprintf(stderr, "usage:./a.out srcfile destfile\n");
        return -1;
    }
    //2.打开源文件和目标文件
    if((sfd=open(argv[1],O_RDONLY))==-1)
    {
        PRINT_ERR("open srcfile error");
    }
    if((dfd=open(argv[2],O_WRONLY|O_CREAT|O_TRUNC,0666))==-1)
    {
        PRINT_ERR("fopen destfile error");
    }
    //3.循环读取拷贝
    while((ret=read(sfd,buf,sizeof(buf)))!=0)
    {
        write(dfd,buf,ret);
    }
    //4.关闭文件
    close(dfd);
    close(sfd);
    return 0;
}

结果展示
在这里插入图片描述

二、stat及相关函数的使用

2.1 stat/getpwuid/getgrgid函数的介绍

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

int stat(const char *pathname, struct stat *statbuf);
功能:获取文件的属性信息
参数:
	@pathname:文件路径及名字
	@statbuf: 属性信息结构体地址
		struct stat
		{
        	dev_t     st_dev;        //文件的设备ID
            //dev_t是设备号的类型:内核识别驱动的编号。文件中相当于磁盘的设备号
            ino_t     st_ino;        //inode号,文件系统识别文件的唯一标号
            mode_t    st_mode;       //文件的类型和权限
                S_IFMT     0170000   //文件类型的掩码位
                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            //管道文件
                如何判断文件类型
                if((st.st_mode) & 0170000 == 0100000 )
                {
                    printf("这是普通文件\n");
                }
           	    如何获取当前文件的权限(8进制表示)
                文件的权限 = (st.st_mode) & 0777
            nlink_t   st_nlink;       //硬链接数,文件别名的个数
            uid_t     st_uid;         //用户的id
            gid_t     st_gid;         //组的id
            dev_t     st_rdev;        //如果是字符或者块设备文件,这里表示的是它的设备号。普通文件没有意义
            // /dev/input/mouse0    13,32 ===>设备号 == 13 <<20 |32
            // 13主设备号,占高12位 (那一类设备)
            // 32次设备号,占低20位 (同类中的哪一个设备)
            off_t     st_size;        //文件大小,单位是字节
            blksize_t st_blksize;     //块的大小,一般是512字节,块是磁盘扇区的倍数,扇区是512字节
            blkcnt_t  st_blocks;      //文件大小,单位是块
            struct timespec st_atim;  //最后一次访问这个文件的时间
            struct timespec st_mtim;  //最后一次修改文件的时间
            struct timespec st_ctim;  //最后一次状态改变的时间(chmod)
		};
返回值:成功返回0,失败返回-1置位错误码

注: 这个函数不能用来获取软连接文件的属性信息,如果想获取软连接文件的属性信息,使用lstat完成

#include <pwd.h>    
struct passwd *getpwuid(uid_t uid);
功能:根据uid获取passwd结构体信息
参数:
    @uid:用户的id
返回值:成功返回passwd结构体指针,失败返回NULL
    struct passwd {
       char   *pw_name;       //用户名
       char   *pw_passwd;     //用户密码
       uid_t   pw_uid;        //uid
       gid_t   pw_gid;        //gid
       char   *pw_gecos;      //用户的信息
       char   *pw_dir;        //用户的家目录
       char   *pw_shell;      //使用的命令行解析器
   };
#include <grp.h>
struct group *getgrgid(gid_t gid);
功能:根据gid获取group结构体信息
参数:
    @gid:组的id
返回值:成功返回group结构体指针,失败返回NULL
    struct group {
        char   *gr_name;       //组名
        char   *gr_passwd;     //组的密码
        gid_t   gr_gid;        //gid
        char  **gr_mem;        //组内成员
    };

2.2 代码示例

使用上述函数统计文件信息。

#include <stdio.h>
#include <grp.h>
#include <pwd.h>    
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#define PRINT_ERR(msg) \
    do                 \
    {                  \
        printf("%s %s %d\n",__FILE__,__func__,__LINE__);      \
        perror(msg);   \
        return -1;     \
    } while (0)

int main(int argc,const char * argv[])
{
    struct stat st;

    if(stat("./io.c",&st))
        PRINT_ERR("get file stat error");

    printf("ino = %ld,type = %#o,mode=%#o,hardlink=%ld,uid=%s,gid=%s,size=%ld\n",
    st.st_ino,st.st_mode & 0170000,st.st_mode&0777,st.st_nlink,
    getpwuid(st.st_uid)->pw_name, //根据uid获取用户名
    getgrgid(st.st_gid)->gr_name, //根据gid获取组名
    st.st_size);

    return 0;
}

结果展示:
在这里插入图片描述

三、获取系统时间的相关函数

3.1 time/localtime函数介绍

#include <time.h>

time_t time(time_t *tloc);
功能:获取秒钟数
参数:
    @tloc:写为NULL
 返回值:成功返回秒钟数,失败返回-1,置位错误码
struct tm *localtime(const time_t *timep);
功能:根据秒钟数转换为tm结构体
参数:
    @timep:秒钟数
返回值:成功返回tm的结构体指针,失败返回NULL
       struct tm {
           int tm_sec;    //秒
           int tm_min;    //分钟
           int tm_hour;   //小时
           int tm_mday;   //天
           int tm_mon;    //月+1
           int tm_year;   //年 +1900
           int tm_wday;   //周几 (0-6, Sunday = 0) 
           int tm_yday;   //一年中的第几天
           int tm_isdst;  //夏令时,在中国已被废弃
       };

3.2 代码示例

获取系统时间

#include <stdio.h>
#include <time.h>
#define PRINT_ERR(msg) \
    do                 \
    {                  \
        printf("%s %s %d\n",__FILE__,__func__,__LINE__);      \
        perror(msg);   \
        return -1;     \
    } while (0)
    
int main(int argc,const char * argv[])
{
    time_t ts;
    struct tm *tm;
    if((ts = time(NULL))==-1)
        PRINT_ERR("get time error");

    if((tm = localtime(&ts))==NULL)
        PRINT_ERR("change time error");
    
    printf("%d-%02d-%02d %02d:%02d:%02d week=%d\n",
    tm->tm_year+1900,tm->tm_mon+1,tm->tm_mday,
    tm->tm_hour,tm->tm_min,tm->tm_sec,tm->tm_wday);
    return 0;
}

结果展示:
在这里插入图片描述

四、综合练习

要求:输入任意文件,输出文件的类型及文件的属性信息

#include <stdio.h>
#include <grp.h>
#include <pwd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <time.h>
#define PRINT_ERR(msg)                                      \
    do                                                      \
    {                                                       \
        printf("%s %s %d\n", __FILE__, __func__, __LINE__); \
        perror(msg);                                        \
        return -1;                                          \
    } while (0)

int main(int argc, const char *argv[])
{
    struct stat st;
    struct tm *tm;
    if (argc != 2)
    {
        fprintf(stderr, "input error,try again\n");
        fprintf(stderr, "usage:./a.out filename\n");
        return -1;
    }
    if (lstat(argv[1], &st))
        PRINT_ERR("get file stat error");

    switch (st.st_mode & 0170000)
    {
    case S_IFSOCK:
        printf("这是套接字文件\n");
        break;
    case S_IFBLK:
        printf("这是块设备文件\n");
        break;
    case S_IFLNK:
        printf("这是软连接文件\n");
        break;
    case S_IFDIR:
        printf("这是目录文件\n");
        break;
    case S_IFCHR:
        printf("这是字符设备文件\n");
        break;
    case S_IFIFO:
        printf("这是管道文件\n");
        break;
    case S_IFREG:
        printf("这是普通文件\n");
        break;
    }

    printf("ino = %ld,mode=%#o,hardlink=%ld,uid=%s,gid=%s,size=%ld\n",
           st.st_ino, st.st_mode & 0777, st.st_nlink,
           getpwuid(st.st_uid)->pw_name, //根据uid获取用户名
           getgrgid(st.st_gid)->gr_name,
           st.st_size);

    //转换出来时间
    if ((tm = localtime(&st.st_atim.tv_sec)) == NULL)
        PRINT_ERR("change time error");

    printf("%d-%02d-%02d %02d:%02d:%02d week=%d\n",
        tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
        tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday);
    return 0;
}

结果展示:
在这里插入图片描述

五、目录操作

5.1 opendir函数

#include <sys/types.h>
#include <dirent.h>

DIR *opendir(const char *name);
功能:打开目录
参数:
    @name:目录的字符串
返回值:成功返回目录的指针,
	   失败返回NULL置位错误码

5.2 readdir函数

#include <dirent.h>

struct dirent *readdir(DIR *dirp);
功能:读取目录下的内容
参数:
    @dirp:目录的指针
返回值:成功返回dirent结构体指针
        失败返回NULL,置位错误码
struct dirent
{
	ino_t          d_ino;       //读取到的文件的inode号
	off_t          d_off;       //不用理会
	unsigned short d_reclen;    //这个结构体的大小
	unsigned char  d_type;      //文件的类型
         DT_BLK      This is a block device.
         DT_CHR      This is a character device.
         DT_DIR      This is a directory.
         DT_FIFO     This is a named pipe (FIFO).
         DT_LNK      This is a symbolic link.
         DT_REG      This is a regular file.
         DT_SOCK     This is a UNIX domain socket.
         DT_UNKNOWN  The file type could not be determined.
             
    char           d_name[256];	 //文件名
};

5.3 closedir函数

#include <sys/types.h>
#include <dirent.h>

int closedir(DIR *dirp);
功能:关闭目录
参数:
    @dirp:目录指针
返回值:成功返回0,失败返回-1置位错误码

5.4 目录操作示例

#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
#define PRINT_ERR(msg)                                      \
    do                                                      \
    {                                                       \
        printf("%s %s %d\n", __FILE__, __func__, __LINE__); \
        perror(msg);                                        \
        return -1;                                          \
    } while (0)

int main(int argc, const char *argv[])
{
    DIR *dir;
    struct dirent *dt;
    if ((dir = opendir("../work")) == NULL)
    {
        PRINT_ERR("opendir error");
    }
    while((dt = readdir(dir)) != NULL)
    {
        switch (dt->d_type)
        {
        case DT_BLK:
            printf("这是块设备文件\n");
            break;
        case DT_CHR:
            printf("这是字符设备文件\n");
            break;
        case DT_DIR:
            printf("这是目录文件\n");
            break;
        case DT_FIFO:
            printf("这是管道文件\n");
            break;
        case DT_LNK:
            printf("这是软连接文件\n");
            break;
        case DT_REG:
            printf("这是普通文件\n");
            break;
        case DT_SOCK:
            printf("这是套接字文件\n");
            break;
        case DT_UNKNOWN:
            printf("未知的文件类型\n");
            break;
        }
        printf("d_name:%s,d_ino:%ld,size:%d\n", dt->d_name, dt->d_ino, dt->d_reclen);
    }
    closedir(dir);
    return 0;
}

结果展示:
在这里插入图片描述
注:这里的size是结构体的大小。

5.5 总结

  1. opendir打开一个目录后得到一个DIR类型的指针给readdir使用。
  2. readdir函数调用一次就会返回一个struct dirent类型的指针,这个指针指向一个结构体变量,这个结构体变量里面记录了一个目录项(所谓目录项就是目录中的一个子文件)。
  3. readdir调用一次只能读出一个目录项,要想读出目录中所有的目录项必须多次调用readdir函数。
  4. readdir函数内部会记住哪个目录项已经被读过了哪个还没读,所以多次调用后不会重复返回已经返回过的目录项。当readdir函数返回NULL时就表示目录中所有的目录项已经读完了。
  5. 最后使用closedir关闭目录。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜猫徐

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值