Linux应用编程之文件属性操作
之前已经谈过Linux系统中对文件内容操作的一些函数和知识,接下来本文要谈的就是怎么操作每个文件的属性,Linux系统中每个文件都有自己的属性,比如权限问题、属主以及时间戳等等,所以了解怎样操作文件属性也是很有必要的。
1. stat函数及其打印内容解释
我们都知道Linux系统中的ls命令,它可以打印某个文件夹下文件属性,其包括权限、属主以及创建权限一些简要信息,而stat虽也是打印文件属性的函数,但不同的是它可以列出非常详细的文件属性内容,以下面这个例子为例:
root@ubuntu:~/linuxApp# stat a.out
File: ‘a.out’
Size: 7572 Blocks: 16 IO Block: 4096 regular file
Device: 801h/2049d Inode: 527897 Links: 1
Access: (0755/-rwxr-xr-x) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2019-07-11 07:04:14.595024093 -0700
Modify: 2019-07-11 07:04:09.763024288 -0700
Change: 2019-07-11 07:04:09.763024288 -0700
Birth: -
stat函数打印出了a.out这个文件的详细文件属性:
| 项目 | 描述 | 值 |
|---|---|---|
| File | 文件名 | ‘a.out’ |
| Size | 文件大小 | 7572B |
| Blocks | 文件所占用磁盘扇区数(每块扇区512B) | 16 |
| IO Block | 文件系统IO时的块大小 | 4096B |
| regular file | 文件类型:普通文件 | |
| Device | 文件存放设备位置 | 801h/2049d |
| Inode | 文件被分配的inode节点序号 | 527897 |
| Links | 指向该文件的硬连接数 | 1 |
| Access | 访问权限 | -rwxr-xr-x |
| Uid | 文件的拥有者 | root |
| Gid | 文件所在的用户组 | root |
| Access | 文件最后一次访问时间 | 2019-07-11 07:04:14.595024093 -0700 |
| Modify | 文件最后一次修改时间(write) | 2019-07-11 07:04:09.763024288 -0700 |
| Change | 文件最后一次更改时间(chmod,link)容易和上一个混淆,可以通过man手册查看更详细的介绍 | 2019-07-11 07:04:09.763024288 -0700 |
| Birth | 这个不太清楚,可能是什么的创建日期 |
stat函数除了是Linux的一个系统命令,它还是Linux系统的API接口函数,其定义可以通过man 2 stat函数查看:
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
int stat(const char *path, struct stat *buf);
int fstat(int fd, struct stat *buf);
int lstat(const char *path, struct stat *buf);
可以看到stat有三种函数,用法大致相同,前两个的差别是stat函数只需要提供文件路径就可以输出文件属性信息,而fstat函数则需要提供打开文件的文件描述符。第一个与第三个函数的区别是在处理链接文件时,第一个会输出链接文件本身的属性,而后者则会输出链接指向文件的文件属性。另外,函数还有一个参数buf,其需要传递一个struct stat类型的指针,表示输出内容的地址,最后函数会返回一个值,-1表示读取失败,0表示成功输出属性内容。
struct stat类型中的结构体成员就是上面表中的各项内容,其定义可以在man手册中查到:
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 */
time_t st_atime; /* time of last access */
time_t st_mtime; /* time of last modification */
time_t st_ctime; /* time of last status change */
};
我们通过这个定义可以的到各个文件属性项的值,比如我们定义一个struct stst tmp,其指向他本身的连接数是tmp.st_nlink,inode值为tmp.st_ino。有一个需要特别注意的是st_mode这个成员,这个成员是一个mode_t变量,它的实质是一个32位的int类型变量,保存了文件的操作权限和文件类型,想要获取其中莫一项的值,比如我们想知道文件是否为一个普通文件,我们需要测试st_mode中某一位是否为1。这样操作有一个坏处就是我们需要记住st_mode每一位的具体含义,所以Linux系统提供了每一位的宏,比如测试文件是否为一个普通文件的宏定义为S_IFREG 0100000 所以我们只需要判断S_IFREG&tmp.st_mode)值是否为0即可判断文件是否是普通文件,其他宏的定义通过man手册可以详细了解,下面我们给出一个打印文件所有读写执行权限的程序实例:
int convert(mode_t mode){
int i = 0;
long tmp = 1;
char buf[10] = {0};
char tt[3] = "rxw";
for(i = 1; i < 10; i++){
if((mode & tmp) != 0){
buf[9 - i] = tt[i % 3];
}
else
buf[9 - i] = '-';
tmp = tmp << 1;
}
printf("File permission is [%s].\n", buf);
return 0;
}
st_mode的后9位按顺序分别是拥有者的读写执行权限、组用户的读写执行权限与其他用户的读写执行权限,所以我们只需依次位操作处理后九位二进制数即可打印出“rw-rw-r”类似的文件权限字符串。
2. 文件权限相关函数
2.1 access函数
access函数用于测试当前执行者是否具有读取被测文件的读写和执行权限,同时也能测试文件是否存在,其定义如下:
#include <unistd.h>
int access(const char *pathname, int mode);
该函数有两个参数,第一个是被测试文件的路径,第二个需要使用系统定义的四个宏:F_OK(文件是否存在)、R_OK(执行者是否具有读权限)、W_OK(执行者是否具有写权限)、X_OK(执行者是否具有执行权限)。当执行者不具有以上要测试的权限或者文件不存在,函数返回-1,否则返回0。
2.2 chmod函数
chmod除了是系统命令外,同样的也是API函数,其作用就是修改文件的读写执行权限的。其定义如下:
#include <sys/stat.h>
int chmod(const char *path, mode_t mode);
int fchmod(int fd, mode_t mode);
其第一个参数是被修改文件的路径,第二个参数用于重写文件属性中的st_mode成员。还有一个函数是fchmod,该函数与chmod的不同之处在于一个需要传递文件路径参数,一个传递的是文件描述符。对于mode位传参有两种方法,一种是重写st_mode值,还有一种是修改某些位:
//增加1.txt文件的其他用户的读权限
chmod("./1.txt", buf.st_mode | S_IROTH);
//删除1.txt文件的其他用户的读权限
chmod("./1.txt", buf.st_mode & (~S_IROTH));
//设置1.txt的权限位为rw-r--r--
chmod("./1.txt", S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
2.3 chown函数
chown也是Linux的命令,其主要作用是修改文件的属主,同样的,系统也提供了API接口用于用户编程,其定义如下:
#include <unistd.h>
int chown(const char *path, uid_t owner, gid_t group);
int fchown(int fd, uid_t owner, gid_t group);
int lchown(const char *path, uid_t owner, gid_t group);
与stat函数的API接口一样,chown也提供三个接口,第一个参数是被修改文件的文件路径,第二个参数是要改为的用户,第三个是要改的组。修改成功函数返回非负整数,失败返回-1,设置erron值。
2.4 umask函数
当我们创建文件时并不需要指定文件的权限,系统会自动设定文件权限,我们如果想要修改文件的默认权限值该怎么办?这就需要用到umask函数,其定义如下:
#include <sys/types.h>
#include <sys/stat.h>
mode_t umask(mode_t mask);
该函数只有一个参数,该参数用法与之前提到的mode_t变量用法相同,既可以使用相关宏复制,也可以用一个int类型的数直接复制比如我们要设置文件默认权限为rw-r–r--,代码可以如下编写:
umask(S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
3. opendir函数与readdir函数
对于文件夹或者文件目录Linux系统提供了了opendir与readdir函数,分别用于打开文件夹文件与读取文件夹中中的文件。opendir函数定义如下:
#include <sys/types.h>
#include <dirent.h>
DIR *opendir(const char *name);
DIR *fdopendir(int fd);
opendir函数的作用就是获取一个可操作的DIR指针变量,我们可以通过这个指针对文件目录进行一些操作,其效果通俗上来讲与文件描述符有点类似。readdir定义如下:
#include <dirent.h>
struct dirent *readdir(DIR *dirp);
int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
readdir用法是传给一个文件目录指针(通过opendir函数返回的),返回目录中一个文件的信息,该信息用struct direct结构体封装。如果要得到文件夹中全部的文件信息,其必须连续调用readdir函数知道返回空指针为止。下面我们给出一个测试root文件夹下共有多少个文件的程序实例:
#include <stdio.h>
#include <sys/types.h>
#include <dirent.h>
void main(){
DIR *tmp;
struct dirent *file;
int count = 0;
tmp = opendir("/root");
file = readdir(tmp);
while(file != NULL){
count++;
printf("%s\n", file->d_name);
file = readdir(tmp);
}
printf("total : %d\n", count);
closedir(tmp);
}
运行程序可以打印出root目录下所有文件名,并进行一个统计。
本文聚焦Linux系统文件属性操作,介绍了stat函数,它能详细列出文件属性,还说明了其三种函数形式及区别。阐述了文件权限相关函数,如access、chmod、chown、umask的作用与用法。此外,介绍了opendir和readdir函数,用于打开和读取文件夹文件。

8497

被折叠的 条评论
为什么被折叠?



