文章目录
- `💡文件操作的系统接口`
- `🍑open系统调用`
- `⚡close系统调用`
- `🦈write系统调用`
- `🦅read系统调用`
- `📚文件管理`
- `📕文件描述符fd `
- `🎈OS管理文件`
- `🌈文件描述符的分配规则`
💡文件操作的系统接口
访问文件会访问到硬件,访问硬件必须要经过OS,所以OS必须提供对应的访问文件的系统调用。
在认识open系统调用之前,先来认识一下两个概念: 系统调用
和 库函数
上面的fopen fclose fread fwrite
都是C标准库当中的函数,我们称之为库函数(libc)。而 open close read write lseek
都属于系统提供的接口,称之为系统调用接口。
🍑open系统调用
简单介绍
:
- 参数:参数一:被打开文件的路径.
- 参数二:标志位(这是一个32的位图,这样可以用 | 传递多个标志).
- 参数三:当文件不存在,需要新建文件的时候,指明文件权限(受系统umask权限掩码的约束)。也就是当文件不存在的时候,我们需要用有三个参数的open。
设置权限掩码接口:umask( ) :只会影响调用它的进程所认为的掩码,其他进程不受影响。
常用的标志位
:
介绍几个常用的:
O_RDONLY:
以读的方式打开。
O_WRONLY:
以写的方式打开,在文件的开头开始覆盖式的写入,并不会将之前的内容清空。
O_CREAT:
如果文件不存在,创建文件。
O_APPEND:
在文件结尾处追加写入。
O_TRUNC:
写入之前清空文件之前的内容。
返回值:
成功返回文件描述符fd,失败返回-1
⚡close系统调用
`
参数介绍
:
- 被关闭的文件的描述符;
返回值介绍
:
- 成功返回0,失败返回-1;
🦈write系统调用
参数介绍
:
- 参数一:目标文件的文件描述符。
- 参数二:要写入的字符串的起始地址。
- 参数三:写入的字符串的长度。
返回值介绍
:
- 成功返回所写的字符串大小,失败返回-1;
代码示例:
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* msg="hello world";
write(fd,msg,strlen(msg));
close(fd);
return 0;
}
🦅read系统调用
参数介绍
:
- 参数一:读取的文件。
- 参数二:将读取的内容放在buf里面。
- 参数三:读取多大的内容。
返回值介绍
:
- 成功返回读取的内容的字节大小,失败返回-1;
代码演示`:
int fd = open("log.txt",O_RDONLY);
if(fd==-1)
{
perror("open");
return 1;
}
char buf[1024];
ssize_t s = read(fd,buf,sizeof(buf));
if(s>0)
{
printf("%s\n",buf);
}
📚文件管理
📕文件描述符fd
通过对open函数的学习,我们知道了文件描述符就是一个小整数。
0 & 1 & 2
Linux进程默认情况下会有3个缺省打开的文件描述符
,分别是标准输入0
, 标准输出1
, 标准错误2
.
0, 1, 2 对应的物理设备一般是:键盘,显示器,显示器
所以输入输出还可以采用如下方式:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
int main()
{
char buf[1024];
ssize_t s = read(0, buf, sizeof(buf));
if(s > 0){
buf[s] = 0;
write(1, buf, strlen(buf));
write(2, buf, strlen(buf));
}
return 0;
}
🎈OS管理文件
现在知道,文件描述符就是从0开始的小整数。当我们打开文件时,操作系统在内存中要创建相应的数据结构来描述目标文件。于是就有了file结构体
。表示一个已经打开的文件对象
。而进程执行open系统调用,所以必须让进程和文件关联起来。每个进程都有一个指针*files, 指向一张表files_struct
,该表最重要的部分就是包涵一个指针数组,每个元素都是一个指向打开文件的指针!所以,本质上,文件描述符就是该数组的下标
。所以,只要拿着文件描述符,就可以找到对应的文件。
🌈文件描述符的分配规则
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
int fd = open("myfile", O_RDONLY);
if(fd < 0){
perror("open");
return 1;
}
printf("fd: %d\n", fd);
close(fd);
return 0;
}
输出:3.
当关闭0或者2,再观察
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main()
{
close(0);
//close(2);
int fd = open("myfile", O_RDONLY);
if(fd < 0){
perror("open");
return 1;
}
printf("fd: %d\n", fd);
close(fd);
return 0;
}
运行结果:关闭0,fd=0;关闭2,fd=2;
结论·:
默认打开的三个流分别占用了 下标0 1 2 的位置。
文件描述符的分配规则
:在files_struct数组当中,找到当前没有被使用的
最小的一个下标,作为新的文件描述符。