【Linux】文件系统(二)
当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file结构体。每个进程都有一个指针*files, 指向一张表files_struct,该表最重要的部分就是包涵一个指针数组,每个元素都是一个指向打开文件的指针!所以,本质上,文件描述符就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件。文件描述符的分配规则:在files_struct数组当中,找到当前没有被使用
💡文件操作的系统接口
在认识返回值之前,先来认识一下两个概念: 系统调用 和 库函数
fopen fclose fread fwrite 都是C标准库当中的函数,我们称之为库函数(libc)。
而, open close read write lseek 都属于系统提供的接口,称之为系统调用接口
回忆一下我们讲操作系统概念时,画的一张图.
系统调用接口和库函数的关系,一目了然。
所以,可以认为,f#系列的函数,都是对系统调用的封装,方便二次开发。
👾open系统调用

参数:
- 参数一:被打开文件的路径.
- 参数二:标志位(这是一个32的位图,这样可以用 | 传递多个标志).
- 参数三:当文件不存在,需要新建文件的时候,指明文件权限(受系统umask权限掩码的约束)。也就是当文件不存在的时候,我们需要用有三个参数的open。
设置权限掩码接口:umask( ) :只会影响调用它的进程所认为的掩码,其他进程不受影响

⌨️参数:
O_RDONLY: 只读打开
O_WRONLY: 只写打开
O_RDWR : 读,写打开
这三个常量,必须指定一个且只能指定一个
O_CREAT : 若文件不存在,则创建它。需要使用mode选项,来指明新文件的访问权限
O_APPEND: 追加写
返回值:
成功返回文件描述符fd,失败返回-1
💻close系统调用

参数介绍:
- 被关闭的文件的描述符;
返回值介绍:
- 成功返回0,失败返回-1;
⚙️ write系统调用

参数介绍:
- 参数一:目标文件的文件描述符。
- 参数二:要写入的字符串的起始地址。
- 参数三:写入的字符串的长度。
返回值介绍:
成功返回所写的字符串大小,失败返回-1;
测试代码:
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
int main()
{
umask(0);
int fd=open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);
if(fd=1)
{
perror("open");
return 1;
}
const char* message="hello world";
write(fd,message,strlen(message));
close(fd);
return 0;
}

📟read系统调用

参数介绍:
- 参数一:读取的文件。
- 参数二:将读取的内容放在buf里面。
- 参数三:读取多大的内容。
返回值介绍:
- 成功返回读取的内容的字节大小,失败返回-1;
测试代码:
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
int main()
{
int fd=open("log.txt",O_RDONLY);
if(fd<0)
{
perror("open");
}
char* buffer[1024];
ssize_t s=read(fd,buffer,sizeof(buffer));
if(s>0)
{
printf("%s\n",buffer);
}
close(fd);
return 0;
}

🧰文件管理
🔗 文件描述符
- 通过对open函数的学习,我们知道了文件描述符就是一个小整数
- Linux进程默认情况下会有3个缺省打开的文件描述符,分别是标准输入0, 标准输出1, 标准错误2.
- 0,1,2对应的物理设备一般是:键盘,显示器,显示器
所以输入输出还可以采用如下方式:

所以输入输出还可以采用如下方式:
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
int main()
{
char buffer[1024];
ssize_t s=read(0,buffer,sizeof(buffer));
if(s>0)
{
buffer[s]=0;
write(1,buffer,sizeof(buffer));
write(2,buffer,sizeof(buffer));
}
return 0;
}
📊OS管理文件
现在知道,文件描述符就是从0开始的小整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file结构体。表示一个已经打开的文件对象。而进程执行open系统调用,所以必须让进程和文件关联起来。每个进程都有一个指针*files, 指向一张表files_struct,该表最重要的部分就是包涵一个指针数组,每个元素都是一个指向打开文件的指针!所以,本质上,文件描述符就是该数组的下标。所以,只要拿着文件描述符,就可以找到对应的文件。
📝文件描述符分配规则
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
int main()
{
int fd=open("log.txt",O_RDONLY);
if(fd==-1)
{
perror("open");
return 1;
}
printf("fd->:%d\n",fd);
close(fd);
return 0;
}

当我们关闭0或者2时再试一次:
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
int main()
{
close(0);
int fd=open("log.txt",O_RDONLY);
if(fd==-1)
{
perror("open");
return 1;
}
printf("fd->:%d\n",fd);
close(fd);
return 0;
}

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<string.h>
int main()
{
//close(0);
close(2);
int fd=open("log.txt",O_RDONLY);
if(fd==-1)
{
perror("open");
return 1;
}
printf("fd->:%d\n",fd);
close(fd);
return 0;
}

运行结果:关闭0,fd=0;关闭2,fd=2;
结论·:
默认打开的三个流分别占用了 下标0 1 2 的位置。
文件描述符的分配规则:在files_struct数组当中,找到当前没有被使用的
最小的一个下标,作为新的文件描述符。
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐


所有评论(0)