💡文件操作的系统接口

在认识返回值之前,先来认识一下两个概念: 系统调用 和 库函数
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数组当中,找到当前没有被使用的
最小的一个下标,作为新的文件描述符。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐