我们在打开一个文件之后,对其进行了读、写操作,那么接下来需要了解一个文件的基本属性,在这里就需要调用stat函数来查看了。
目录
一、获取文件元信息
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *pathname, struct stat *statbuf);
int fstat(int fd, struct stat *statbuf);
int lstat(const char *pathname, struct stat *statbuf);
我们主要研究stat函数
path:文件地址 buf:存储文件元信息的结构体
函数成功执行后,所得的元信息都存储在buf中
成功0.失败-1
buf结构体的数据:
struct stat {
dev_t st_dev; /* ID of device containing file */
ino_t st_ino; /* Inode number */
mode_t st_mode; /* File type and mode */
nlink_t st_nlink; /* Number of hard links */
uid_t st_uid; /* User ID of owner */
gid_t st_gid; /* Group ID of owner */
dev_t st_rdev; /* Device ID (if special file) */
off_t st_size; /* Total size, in bytes */
blksize_t st_blksize; /* Block size for filesystem I/O */
blkcnt_t st_blocks; /* Number of 512B blocks allocated */
/* Since Linux 2.6, the kernel supports nanosecond
precision for the following timestamp fields.
For the details before Linux 2.6, see NOTES. */
struct timespec st_atim; /* Time of last access */
struct timespec st_mtim; /* Time of last modification */
struct timespec st_ctim; /* Time of last status change */
#define st_atime st_atim.tv_sec /* Backward compatibility */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};
具体的中文翻译可以参考stat函数与stat结构体 和 Linux中stat函数和stat命令使用详解
这里着重说明一下st_mode,它是一个16bit的整形数,各个bit所对应的关系如下
0-2比特位 | 其他用户权限 |
3-5比特位 | 组用户权限 |
6-8比特位 | 本用户权限 |
9-11比特位 | 特殊权限 |
12-15比特位 | 文件类型 |
所以想要使用文件权限和类型的时候,要先用st_mode与一系列的宏做&运算之后才能得出,具体的操作一样可以参考上一个链接。
以及st_blocks,指的是文件所占的块数,1块-->512Byte
二、对应stat结构体部分成员的操作函数
1、getpwuid函数
#include <sys/types.h>
#include <pwd.h>
struct passwd *getpwuid(uid_t uid);
uid_t uid:指的是stat结构体里边的uid。
功能:返回/etc/passwd文件里指定uid的行,把这一行的信息放入结构体passwd中。
关于/etc/passwd,请参考 Linux /etc/passwd
passwd结构体如下:
struct passwd {
char *pw_name; /* username */
char *pw_passwd; /* user password */
uid_t pw_uid; /* user ID */
gid_t pw_gid; /* group ID */
char *pw_gecos; /* user information */
char *pw_dir; /* home directory */
char *pw_shell; /* shell program */
};
2、getgrgid函数
#include <sys/types.h>
#include <grp.h>
struct group *getgrgid(gid_t gid);
gid_t gid:指的是stat结构体里边的gid。
功能:返回/etc/group文件里指定gid的行,把这一行的信息放入结构体group中。
group结构如下:
struct group {
char *gr_name; /* group name */
char *gr_passwd; /* group password */
gid_t gr_gid; /* group ID */
char **gr_mem; /* NULL-terminated array of pointers
to names of group members */
};
3、localtime函数
#include <time.h>
struct tm *localtime(const time_t *timep);
const time_t *timep指的是stat结构体中包含的三个时间结构体中的某一个成员,最下边三行有现成的宏定义可以使用
(宏定义里的时间是当前时间到1970.1.1 00:00:00的秒数)
功能:将秒数转化为一个tm类型的结构体
tm结构体如下:
struct tm {
int tm_sec; /* Seconds (0-60) */
int tm_min; /* Minutes (0-59) */
int tm_hour; /* Hours (0-23) */
int tm_mday; /* Day of the month (1-31) */
int tm_mon; /* Month (0-11) */
int tm_year; /* Year - 1900 */
int tm_wday; /* Day of the week (0-6, Sunday = 0) */
int tm_yday; /* Day in the year (0-365, 1 Jan = 0) */
int tm_isdst; /* Daylight saving time */
};
我们可以直接调用tm结构体中的数据进行操作,也可以调用strftime()函数拼接成字符串使用。
4、strftime函数
#include <time.h>
size_t strftime(char *s, size_t max, const char *format, const struct tm *tm);
功能:将 tm 结构体中的数据,按照 format 所指定的字符串格式,保存到字符串 s 中,最多保存max字节。(具体的使用在最下方的例子中)
format中使用到的特殊格式说明符可以参照 百度百科strftime()函数
5、time函数
如果需要获取单独的时间戳,可以调用time函数,可以获取当前时间到1970.1.1 00:00:00的秒数。
#include <time.h>
time_t time(time_t *tloc);
time_t *tloc是存放时间的结构体,函数的返回值是结构体的地址
三、具体的函数使用实例
其中的目录解析函数请参考 关于目录的基本函数
mian.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include "myls.h"
#include <glob.h>
#include <string.h>
#define BUFSIZE 128
int main(int argc, char *argv[]){
int c = 0;
struct stat st;
char *p = "./*";
char *path = NULL;
glob_t res;
char buf[BUFSIZE] = {};
c = getopt(argc ,argv, "-l");
switch (c){
case 1 :
strcat(strcpy(buf,argv[optind-1]),"/*");
glob(buf, 0, NULL, &res);
for (int i = 0; i < res.gl_pathc; i++)
printf("%s\t",(res.gl_pathv)[i]);
printf("\n");
globfree(&res);
break;
case 'l':
glob(p, 0, NULL, &res);
for (int i = 0; i < res.gl_pathc; i++){
path = (char *)res.gl_pathv[i];
stat(path, &st);
printf("%c%s %d %s %s %d %s %s\n", filetype(st),filemode(st),\
filenlink(st),fileowner(st), filegroupname(st), \
filesize(st), filetime(st), res.gl_pathv[i]);
}
globfree(&res);
break;
}
if (argc < 2){
glob(p, 0, NULL, &res);
for (int i = 0; i < res.gl_pathc; i++)
printf("%s\t",(res.gl_pathv)[i]);
printf("\n");
globfree(&res);
}
return 0;
}
myls.h
#ifndef __MYLS_H
#define __MYLS_H
const char *filemode(struct stat st);
char filetype(struct stat st);
int filenlink(struct stat st);
const char *fileowner(struct stat st);
const char *filegroupname(struct stat st);
int filesize(struct stat st);
const char *filetime(struct stat st);
#endif
myls.c
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#define BUFSIZE 32
const char *filemode(struct stat st){ // 文件权限
int m[] = {S_IRUSR,S_IWUSR,S_IXUSR,S_IRGRP,S_IWGRP,S_IXGRP,S_IROTH,S_IWOTH,S_IXOTH};
static char s[] = "rwxrwxrwx";
for (int i = 0; s[i]; i++){
if (!(st.st_mode & m[i]))
s[i] = '-';
}
return s;
}
char filetype(struct stat st){ //文件类型
char ret;
switch (st.st_mode & S_IFMT){
case S_IFSOCK: ret = 's'; break;
case S_IFLNK : ret = 'l'; break;
case S_IFREG : ret = '-'; break;
case S_IFBLK : ret = 'b'; break;
case S_IFDIR : ret = 'd'; break;
case S_IFCHR : ret = 'c'; break;
case S_IFIFO : ret = 'p'; break;
}
return ret;
}
int filenlink(struct stat st){ //文件链接数
return st.st_nlink;
}
const char *fileowner(struct stat st){ //文件拥有者名
struct passwd *pwd = getpwuid(st.st_uid);
return pwd->pw_name;
}
const char *filegroupname(struct stat st){ //文件所属组
struct group *grp = getgrgid(st.st_gid);
return grp->gr_name;
}
int filesize(struct stat st){ //文件大小
return st.st_size;
}
const char *filetime(struct stat st){ //文件最后一次修改时间
static char buf[BUFSIZE] = {};
struct tm *tmp = localtime(&st.st_mtime);
strftime(buf, BUFSIZE, "%m月 %d %H:%M",tmp);
return buf;
}