有三个文件属性查看的API:stat、fstat、lstat。 #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> int stat(const char *pathname, struct stat *buf); int fstat(int fd, struct stat *buf); int lstat(const char *pathname, struct stat *buf); #include <fcntl.h> /* Definition of AT_* constants */ #include <sys/stat.h> int fstatat(int dirfd, const char *pathname, struct stat *buf,int flags); stat不用打开文件,fstat需要打开文件,lstat主要是符号链接文件,查询链接文件本身。 struct stat是一个内核定义结构体,在#include <sys/stat.h>声明,这个里面的内容加起来就是文件属性信息。里面的各个元素就是各种属性。 struct stat { dev_t st_dev; /* ID of device containing file */ ino_t st_ino; /* inode number */ mode_t st_mode; /* protection */ 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; /* blocksize 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 }; 在ubantu16.04命令行中输入 stat XXX: 文件:‘a.out‘ 大小:8968 块:18 IO 块:1024 普通文件 设备:2ah/42d Inode:5331 硬链接:1 权限:(0777/-rwxrwxrwx) Uid:( 0/ root) Gid:( 0/ root) 最近访问:2018-08-12 12:29:37.000000000 +0800 最近更改:2018-08-12 12:29:37.000000000 +0800 最近改动:2018-08-12 12:29:37.000000000 +0800 创建时间:- 上诉信息就为结构体里面数据。 下面非常简单的测试函数 #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <string.h> #define FILENAME "1.txt" int main (void) { int ret = -1; struct stat buf; memset(&buf, 0, sizeof(buf)); ret = stat(FILENAME,&buf); if(ret<0) { perror("ret:"); _exit(-1); } printf("st_ino = %d\n",buf.st_ino); printf("st_size = %d\n",buf.st_size); printf("st_blksize = %d\n",buf.st_blksize); printf("st_blocks = %d\n",buf.st_blocks); return 0; } 如下为应用案例: 1、判断文件类型 文件类型在st_mode里面,这里面是为操作的,类似于CPSR寄存器。linux中有很多宏来进行操作位的测试。如下 S_ISREG(m) is it a regular file? S_ISDIR(m) directory? S_ISCHR(m) character device? S_ISBLK(m) block device? S_ISFIFO(m) FIFO (named pipe)? S_ISLNK(m) symbolic link? (Not in POSIX.1-1996.) S_ISSOCK(m) socket? (Not in POSIX.1-1996.) S_ISREG这个宏返回1,则是普通文件,若不是就返回0.结果就是若是这个文件则是返回1,不是返回0.此外,st_mode还记录了文件权限。测试方法和文件类型相似,使用位掩码,但是没有宏操作。由于很多,不再一一列举,可通过man 2 stat查看。 简单测试代码: unsigned int result = buf.st_mode & (S_IRUSR >> 8); printf("file owner :%X\n",result); 对于文件来说,很重要的一部分就是文件的权限管理。 st_mode本质上一个三十二位的二进制,类型差不多就是unsigned int,反正差不多。 在操作之前需要对文件进行权限规则检查: 1、文件有9个权限位(owner,group,others) 2、若是a.out为例,是看什么执行了a.out,也就是当前进程,是哪个用户进程。 在linux下面可以通过access函数来判断是否有执行权限,可以测试得到当前用户当前环境对目标文件是否有某种操作权限。 #include <unistd.h> int access(const char *pathname, int mode); 具体可通过man 2 access查看。 chowd和fchowd和lchowd 通过man 2 chmod查看,是用修改文件属主。 文件掩码umask是linux中的一个全局设置,作用就是设定我们系统新创建权限。 对于目录文件,包含子文件的文件。 opendir与readdir #include <sys/types.h> #include <dirent.h> DIR *opendir(const char *name); DIR *fdopendir(int fd); #include <dirent.h> struct dirent *readdir(DIR *dirp); int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result); struct dirent { ino_t d_ino; /* inode number */ off_t d_off; /* not an offset; see NOTES */ unsigned short d_reclen; /* length of this record */ unsigned char d_type; /* type of file; not supportedby all filesystem types */ char d_name[256]; /* filename */ }; 每调用readdir一次只能读出一个,要想读出目录中的所有目录项,那么必须多次读取,readdir函数内部记住那个目录已经被调用的,不会回返已经读取的目录项,要是readdir要是返回NULL就表示已经读取完了。简单的测试函数如下: #include <stdio.h> #include <dirent.h> #include <sys/types.h> #include <dirent.h> int main(int argc,char **argv) { DIR *pDir = NULL; struct dirent *pEnt = NULL; if(argc !=2) { printf("error"); return 0; } pDir = opendir(argv[1]); if(NULL == pDir) { perror("opendir:\n"); return -1; } while(1) { pEnt = readdir(pDir); if(pEnt != NULL) { printf("name:%s\n",pEnt->d_name); } else { break; } } return 0; } 可重入函数:readdir函数和以前接触的函数是不同的,这个函数直接返回了一个结构体指针。因readdir内部申请了内存并且给了我们地址,多次调用readdir其实不会重复申请内存而是使用第一次调用readdir是分配的那个内存,所以设计方法是readdir不可重入的关键。 库函数有一些函数是不可重入的,后来意识到这个中不安全,后来重新封装了C库函数,一般是不可重入函数后面加入_r变成可重入的函数。
朱友鹏老师视频学习笔记