1、stat 命令
stat filename ,功能上类似于 ls - l。
2、stat 函数
(1)头文件:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
(2)原型:
int stat(const char *pathname, struct stat *buf);
(3)参数:
1)pathname :文件名称(包含路径,不写默认当前目录下)。
2)buf : 结构体:结构体元素为文件信息。
(4)返回值:
成功返回 0; 失败返回 -1,设置 erron 。
3、使用 stat 函数获得文件大小
struct stat st;
int ret = stat(“bigtext.txt”, &st);
if(ret == -1){
perror(“stat error”);
exit(1);
}
printf(“file size = %d\n”, (int)st.st_size); // 注意类型强转,否则编译有警告
4、使用 stat 函数获得文件类型和权限
对应结构体中的元素是 mode_t 和st_mode。
类型:
(1)mode_t (本质是一个 16 位的整数,也称位图)。
(2)st_mode :16 位整数,分 5 块(特殊权限位不需要掌握),如下图所示:
(1)0-2 bit :其他人权限
1)宏:S_IROTH ;八进制数:0004 ;权限:读权限。
2)宏:S_IWOTH ;八进制数:0002 ;权限:写权限 。
3)宏:S_IXOTH ;八进制数:0001 ;权限:执行权限 。
(2) 3-5 bit :所属组权限
1)宏:S_IRGRP;八进制数: 0040 ;权限:读权限 。
2)宏:S_IWGRP ;八进制数:0020 ;权限:写权限。
3)宏: S_IXGRP ;八进制数:0010 ;权限:执行权限。
(3) 6-8 bit : 文件所有者权限
1)S_IRUSR ;0400 ;读权限。
2)S_IWUSR ;0200; 写权限。
3)S_IXUSR ;0100; 执行权限。
(4)12-15 bit :文件类型
1)S_IFSOCK ;140000 ;套接字 。
2)S_IFLNK ;120000; 符号连接(软链接)。
3)S_IFREG ;100000 ;普通文件。
4)S_IFBLK ;060000 ;块设备。
5)S_IFDIR ;040000; 目录。
6)S_IFCHR ;020000; 字符设备。
7)S_IFIFO ;010000 ;管道。
8)S_IFMT ;170000; 掩码。
5、stat 、 lstat 、fstat 的 区别
int stat(const char *pathname, struct stat *buf);
int lstat(const char *pathname, struct stat *buf); // 前两个函数形式基本一样
int fstat(int fd, struct stat *buf);
主要是在查看软链接文件时候有区别:
(1)stat 是 读取“软链接指向的文件”的属性 (穿透软链接)。
(2)lstat 是 读取“软链接本身文件”的属性(不穿透软链接)。
(3)fstat 是使用 open 打开文件后,通过文件描述符读取文件属性。
6、实现 ls -l filename
代码如下:
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <string.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
int main(int argc, char *argv[])
{
if(argc < 2){
perror("./a.out filename\n");
return -1;
}
struct stat sb ;
if( lstat(argv[1], &sb ) < 0 ) // 函数调用失败,打印错误信息,否则不执行if,表示获得信息成功
{
perror("stat err");
return -1;
}
// 代码执行到这个位置,意味着获得信息成功
char fileMode[11] = {0}; // 比如 drwxr-xr-x 字符串 共10位+ \0
memset( fileMode, '-', 10); // 最后一位不格式
//先搞定文件类型
if(S_ISREG(sb.st_mode)) fileMode[0] = '-'; // regular file
if(S_ISDIR(sb.st_mode)) fileMode[0] = 'd'; // directory
if(S_ISCHR(sb.st_mode)) fileMode[0] = 'c'; // character device
if(S_ISBLK(sb.st_mode)) fileMode[0] = 'b'; // block device
if(S_ISFIFO(sb.st_mode)) fileMode[0] = 'p'; // FIFO (named pipe)
if(S_ISLNK(sb.st_mode)) fileMode[0] = 'l'; // symbolic link
if(S_ISSOCK(sb.st_mode)) fileMode[0] = 's'; // socket
//在搞定三类用户的权限
//用户
if(S_IRUSR & sb.st_mode) fileMode[1] = 'r'; // 否则因为memset ,默认是 ’-’
if(S_IWUSR & sb.st_mode) fileMode[2] = 'w';
if(S_IXUSR & sb.st_mode) fileMode[3] = 'x';
//组用户
if(S_IRGRP & sb.st_mode) fileMode[4 ]= 'r';
if(S_IWGRP & sb.st_mode) fileMode[5] = 'w';
if(S_IXGRP & sb.st_mode) fileMode[6] = 'x';
//其他用户
if(S_IROTH & sb.st_mode) fileMode[7] = 'r';
if(S_IWOTH & sb.st_mode) fileMode[8] = 'w';
if(S_IXOTH & sb.st_mode) fileMode[9] = 'x';
//获得用户名和组名
char *User = getpwuid(sb.st_uid)->pw_name;
char *Group = getgrgid(sb.st_gid)->gr_name;
//获得时间
struct tm *fileTm = localtime(&sb.st_ctim.tv_sec);
printf("%s %ld %s %s %ld %d月 %d %d:%d %s\n", fileMode, sb.st_nlink, User, Group, sb.st_size,
fileTm->tm_mon+1, fileTm->tm_mday, fileTm->tm_hour, fileTm->tm_min,
argv[1]);
return 0;
}