有三个文件属性查看的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
",buf.st_ino);
printf("st_size = %d
",buf.st_size);
printf("st_blksize = %d
",buf.st_blksize);
printf("st_blocks = %d
",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
",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:
");
return -1;
}
while(1)
{
pEnt = readdir(pDir);
if(pEnt != NULL)
{
printf("name:%s
",pEnt->d_name);
}
else
{
break;
}
}
return 0;
}
可重入函数:readdir函数和以前接触的函数是不同的,这个函数直接返回了一个结构体指针。因readdir内部申请了内存并且给了我们地址,多次调用readdir其实不会重复申请内存而是使用第一次调用readdir是分配的那个内存,所以设计方法是readdir不可重入的关键。
库函数有一些函数是不可重入的,后来意识到这个中不安全,后来重新封装了C库函数,一般是不可重入函数后面加入_r变成可重入的函数。
朱友鹏老师视频学习笔记