Linux文件属性
1.Linux中常见文件类型
- 普通文件(- regular file)
- 目录文件(d directory)
- 字符设备文件(c character)
- 块设备文件(b block)
- 管道文件(p pipe)
- 套接字文件(s socket)
- 符号链接文件(l link)
2.常用文件属性获取
2.1stat命令获取文件信息
stat :display file or file system status
样例:
peco@ubuntu:~/linux_pro$ stat a.out
File: 'a.out'
Size: 8912 Blocks: 24 IO Block: 4096 regular file
Device: 801h/2049d Inode: 1983571 Links: 1
Access: (0755/-rwxr-xr-x) Uid: ( 1000/ peco) Gid: ( 1000/ aston)
Access: 2019-04-08 15:34:43.295173788 +0800
Modify: 2019-04-08 15:34:41.807173752 +0800
Change: 2019-04-08 15:34:41.807173752 +0800
Birth: -
其中size是文件大小,Access是文件最后一次被访问(打开,读取,修改等)的时间,Modify是文件内容最后一次被修改的时间,Change是文件属性最后一次被改变的时间。
2.2 系统调用(stat、fstat、lstat)获取文件信息
stat, fstat, lstat : get file status
#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);
struct stat是内核定义的一个结构体,在<sys/stat.h>中声明,该结构体中的所有元素加起来就是文件属性信息。
struct stat:
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
};
三个API的区别:
- stat()让内核将要查找属性文件的属性信息结构体的值放入传递给stat函数的buf中,stat调用成功从内核返回时buf中就被填充了文件的正确属性信息,然后通过查看buf结构体变量的元素就可以得知文件的各种属性了。
- fstat()是由一个已经打开的文件fd出发得到一个文件的属性信息。所以如果文件没有打开(即不想打开文件而只想得到文件属性)那就用stat,如果文件已经被打开然后想得到属性那就用fstat,这样效率会更高(因为stat从磁盘去读取文件,fstat是从内存读取动态文件)。
- lstat():对于符号链接文件,stat和fstat查阅的是符号链接文件指向的文件的属性,而lstat查阅的是符号链接文件本身的属性。
3.文件权限管理
3.1文件权限位
一个具有9个权限位,3个一组。比如:
-rwxr-xr-x 1 peco aston 8912 Apr 8 15:34 a.out
第一组三个(rwx)表示文件的属主(owner、user)对该文件的可读、可写、可执行权限;第2组3个位(r-x)表示文件的属主所在的组(group)对该文件的权限;第3组3个位(r-x)表示其他用户(others)对该文件的权限。
3.2access函数
access函数可以测试得到当前执行程序用户在当前环境下对目标文件是否具有某种操作权限。
access: check user's permissions for a file
#include <unistd.h>
int access(const char *pathname, int mode);
其中参数pathname 是文件的路径名,参数 mode指定access的作用,取值如下:
mode | 含义 |
---|---|
F_OK (0) | 判断对文件是可执行权限 |
X_OK (1) | 判断对文件是否有写权限 |
W_OK(2) | 判断对文件是否有写权限 |
R_OK (4) | 判断对文件是否有读权限 |
后三种可以一起使用,如W_OK|R_OK。
access示例:
#include <stdio.h>
#include <unistd.h>
int main(int argc,char**argv)
{
int ret = -1;
char* file_path="./test.txt";
ret = access(file_path, F_OK);
if (ret < 0){
printf("%s is not exist! \n",file_path);
return -1;
}
else{
printf("%s exist! \n",file_path);
}
ret = access(file_path, R_OK);
if (ret < 0){
printf("can not read %s !\n",file_path);
}
else{
printf("can read %s !\n",file_path);
}
ret = access(file_path, W_OK);
if (ret < 0){
printf("can not write %s !\n",file_path);
}
else{
printf("can write %s !\n",file_path);
}
ret = access(file_path, X_OK);
if (ret < 0){
printf("can not excute %s ! \n",file_path);
}
else{
printf("can excute %s \n",file_path);
}
return 0;
}
3.3chmod函数
chmod是一个用来修改文件的各种权限属性的命令。chmod命令只有root用户才有权利去执行修改,它内部是用linux的一个叫chmod的API实现的。
chmod: change permissions of a file
#include <sys/stat.h>
int chmod(const char *pathname, mode_t mode);
4.读取目录文件
4.1opendir与readdir函数
opendir:
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
readdir:
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
struct dirent:
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 supported
by all filesystem types */
char d_name[256]; /* filename */
};
- opendir()打开一个目录后得到一个DIR类型的指针给readdir使用。
- readdir()调用一次就会返回一个struct dirent类型的指针,这个指针指向一个记录了一个目录项(目录中的一个子文件)的结构体变量。
- readdir()调用一次只能读出一个目录项,要想读出目录中所有的目录项必须多次调用readdir函数。readdir函数内部会记住哪个目录项已经被读过了哪个还没读,所以多次调用不会重复返回已经返回过的目录项。当readdir函数返回NULL时就表示目录中所有的目录项已经读完了。
4.2可重入函数介绍
- 有些函数是可重入的有些是不可重入的,具体概念见此博客Linux:可重入函数与不可重入函数。
- readdir函数和前面接触的一些函数是不同的,首先readdir函数直接返回了一个结构体变量指针,因为readdir内部申请了内存并且返回了地址。多次调用readdir其实readir内部并不会重复申请内存而是使用第一次调用readdir时分配的那个内存。这个设计方法是readdir不可重入的关键。
- readdir在多次调用时是有关联的,这个关联也标明readdir函数是不可重入的。 库函数中有一些函数当年刚开始提供时都是不可重入的,后来意识到这种方式不安全,所以重新封装了C库,提供了对应的可重复版本(一般是不可重入版本函数名_r)