@[toc]
前言
上一篇文章介绍了一下关于在Linux中对于文件操作的简单函数,但是只学习了简单函数对文件的一些复杂操作是不太行的,所以这篇文章给大家介绍一下对文件操作的一些复杂函数。
一、stat函数
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 *statbuf)
int lstat(const char* pathname, struct stat* buf);
功能:
获取文件状态信息
stat和lstat的区别:
当文件是一个符号链接时,lstat返回的是该符号链接本身的信息;
而stat返回的是该链接指向的文件的信息。
参数:
path:文件名
buf:保存文件信息的结构体
返回值:
成功:0
失败:-1
而这个结构体struct stat
中的结构如下:
struct stat {
dev_t st_dev; /* 包含文件的设备ID */
ino_t st_ino; /* Inode编号 */
mode_t st_mode; /* 文件类型和模式 */
nlink_t st_nlink; /* 硬链接数 */
uid_t st_uid; /* 所有者的用户ID */
gid_t st_gid; /* 组ID */
dev_t st_rdev; /* 设备ID(如果特殊文件) */
off_t st_size; /* 总大小,以字节为单位 */
blksize_t st_blksize; /* 文件系统I/O的块大小 */
blkcnt_t st_blocks; /* 已分配512B块的数量 */
/* 从Linux 2.6开始,内核支持纳秒
以下时间戳字段的精度。
Linux 2.6之前版本的详细信息请参见“说明”。 */
struct timespec st_atim; /* 最后一次访问时间 */
struct timespec st_mtim; /* 最后一次修改时间 */
struct timespec st_ctim; /* 最后一次状态更改的时间 */
#define st_atime st_atim.tv_sec /* 向后兼容性 */
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
};
比如说查看一个文件的信息,代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
int main(){
struct stat ps;
int ret;
ret = stat("demo1.c", &ps);
if (ret == -1){
perror("stat");
return -1;
}
printf("%ld", ps.st_dev);
return 0;
}
上面的代码是查看了一下设备的ID,需要注意的是,在创建结构体的时候不能使用指针的形式,也就是创建struct stat*
,这样子是不可以的,如果使用了会出现下面的错误:
stat:bad address
下面就会有一道题,就是使用stat
获取文件的用户权限,代码如下:
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
int main(){
int ret;
struct stat ps;
ret = stat("demo1.c", &ps);
if (ret == -1){
perror("stat");
return -1;
}
if (ps.st_mode & 0400){
printf("r");
}
else{
printf("-");
}
if (ps.st_mode & 0200){
printf("w");
}
else{
printf("-");
}
if (ps.st_mode & 0100){
printf("x");
}
else{
printf("-");
}
printf("\n");
return 0;
}
运行后的结果如下:
rw
二、access函数
这个函数是来判断文件是否有某种权限的,函数的原型如下:
#include <unistd.h>
int access(const char* pathname, int mode);
功能:测试指定文件是否具有某种属性
参数:
pathname:文件名
mode:文件权限,4种权限
R_OK: 是否有读写权限
W_OK: 是否有写权限
X_OK: 是否有执行权限
F_OK: 测试文件是否存在
返回值:
0:有某种权限,或文件存在
-1:没有,或文件不存在
这个函数相当于来说比较简单,比如说判断一下demo1.c
这个文件中是否存在读写权限,那么代码如下:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(){
int ret;
ret = access("demo1.c", R_OK);
if (ret == -1){
perror("access");
return -1;
}
else if(ret == 0){
printf("文件有读的权限\n");
}
return 0;
}
三、chmod函数
chmod
是Linux中的一个指令,是用来修改一个文件的权限的指令,而这里讲的chmod
函数也是
来修改文件的权限的,只不过需要我们像调用函数一样调用它。chmod
函数的原型如下:
#include <sys/stat.h>
int chmod(const char* pathname, mode_t mode);
功能:修改文件权限
参数:
filename:文件名
mode:权限(8进制数)
返回值:
成功:0
失败:-1
例如下面的代码:
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
int main(){
int ret;
ret = chmod("text", 0000);
if (ret == -1){
perror("chmod");
return -1;
}
return 0;
}
将text文件的权限修改为0000
,之前text的权限为:
-rw-rw-r--
执行上面代码后text文件的权限为:
---------
可以发现权限是已经进行了修改。
四、chown函数
这个函数是修改文件所属组和角色的函数,和命令的用法一样,函数的原型如下:
#include <unistd.h>
int chown(const char* pathname, uid_t owner, git_t group);
功能:
修改文件所有者和所属组
参数:
pathname:文件或目录名
owner:文件所有者id,通过查看 /etc/passwd 得到所有者id
group:文件所属组id,通过 /etc/group 得到用户组id
返回值:
成功:0
失败:-1
需要注意一下,这里的owner
和group
得填写用户和组的id,需要去到/etc/passwd
和etc/group
文件中去查看,在命令行中输入下面的命令即可查看其中的内容:
cat /etc/passwd
cat /etc/group
可以看到,用户root的id为0,那如果要修改的话就可以在owner
这填写0,组也是同样的操作。
如果不想动这个文件的所属组或者所属用户,那可以直接填写-1,这样就可以不修改了。
下面的代码是修改text文件的所属用户:
#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
int main(){
int ret;
ret = chown("text", 1004, -1);
if (ret == -1){
perror("chown");
return -1;
}
return 0;
}
编译后并执行会发现这个程序并没有执行成功,并输出了下面的语句:
chown: Operation not permitted
原因是因为当前用户的权限并不高,如果要执行得需要更高的权限,所以这里需要切换至root
用户再来进行执行,这样就能成功的执行了。
五、truncate函数
这个函数是可以修改文件的大小的函数,函数原型如下:
#include <unistd.h>
#include <sys/types.h>
int truncate(const char* path, off_t length);
功能:修改文件大小
参数:
path:文件名字
length:指定的文件大小
a)比用来小,删除后边的部分
b)比原来大,向后拓展
返回值:
成功:0
失败:-1
比如说我创建了一个文件叫做text1
长度为:4,现在我写好了一个程序,程序主要是修改这个文件的大小为100,代码如下:
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
int main(){
int ret;
ret = truncate("text1", 100);
if (ret == -1){
perror("truncate");
return -1;
}
return 0;
}
执行完这个程序后,查看这个文件的大小,会发现它变成了:100
文件中的内容也增加了一些:
会发现这后面增加的内容看不明白,那这些是什么呢?其实这些就是空洞,后面对文件操作或者是内存操作文件会经常见到,这出现的原因主要是因为你本来写的东西只有4个(3个字符1个\0
),而现在要求扩大这个文件,所以就需要一些占位的内容,所以这些占位的内容就是使用空洞来进行占位。
我再修改一下这个文件,将它的大小变为100
然后我将这个文件的大小修改为10,看看这个文件会发生什么。
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
int main(){
int ret;
ret = truncate("text1", 10);
if (ret == -1){
perror("truncate");
return -1;
}
return 0;
}
可以看到多出来的内容就全部被截断了,只留下长度为10的内容。
六、rename函数
这个函数是将文件进行改名的函数,函数原型如下:
#include <stdio.h>
int rename(const char* oldpath, const char* newpath);
功能:把oldpath的文件名改成newpath
参数:
oldpath:旧文件名
newpath:新文件名
返回值:
成功:0
失败:-1
总结
这些函数都是比较简单的,大家多练习就可以熟练掌握。
这个网站是我搬运我CSDNsha上的,其实是为了拿个礼品所以搬运的,大家可以看看CSDN上的:https://blog.csdn.net/zagzag001/article/details/130501131