有三个文件属性查看的 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 变成可重入的函数.
朱友鹏老师视频学习笔记
来源: http://www.bubuko.com/infodetail-2726974.html