Linux应用编程之文件属性操作

本文聚焦Linux系统文件属性操作,介绍了stat函数,它能详细列出文件属性,还说明了其三种函数形式及区别。阐述了文件权限相关函数,如access、chmod、chown、umask的作用与用法。此外,介绍了opendir和readdir函数,用于打开和读取文件夹文件。


之前已经谈过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目录下所有文件名,并进行一个统计。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值