操作系统之系统IO

🌟 各位看官好,我是 maomi_9526

🌍 种一棵树最好是十年前,其次是现在!

🚀 今天来学习C语言的相关知识。

👍 如果觉得这篇文章有帮助,欢迎您一键三连,分享给更多人哦

目录

[1. 文件的概念](#1. 文件的概念)

[2. C语言文件操作接口](#2. C语言文件操作接口)

[3. 系统调用与文件I/O](#3. 系统调用与文件I/O)

3.1标志位传递方法

3.2系统调用

3.2.1open

3.2.2权限掩码(umask)

3.3文件描述符

3.3.1操作系统

3.3.2默认文件描述符0&1&2

3.3.3文件描述符的分配规则

3.4重定向

1. 文件的概念

  • 狭义理解

    • 文件是存储在磁盘上的永久性数据,通过磁盘进行I/O操作。
  • 广义理解

    • 在Linux中,几乎一切都可以看作是文件(包括硬件设备如键盘、显示器、磁盘、进程等)。
  • 文件操作

    • 文件包括文件的元数据和内容,所有操作可以分为文件内容操作和文件属性操作。

    • 文件操作并非是通过C/C++语言库函数进行实现的,而是通过调用文件相关的系统的接口进行实现的的。

2. C语言文件操作接口

  • 打开文件 :使用 fopen() 来打开文件,可以选择不同的文件模式(如 r, w, a 等)。
  • 写入文件 :使用 fwrite() 向文件写入数据,fclose() 用于关闭文件。

  • 读取文件 :使用 fread() 从文件中读取数据,feof() 用于检测文件末尾。

  • 标准输出 :可以使用 printf()fwrite()fprintf() 向标准输出流(stdout)输出数据。

    #include<stdio.h>
    int main()
    {
    FILE* fp=fopen("file","W");
    if(!fp)
    {
    printf("fopen error");
    }
    while(1);
    fclose(fp);
    return 0;
    }

简单回顾程序执行:

  • cwd:指向当前进程运行目录的一个符号链接。
  • exe:指向启动当前进程的可执行文件(完整路径)的符号链接。
  • 打开文件,本质是进程打开,所以,进程知道自己在哪里,即便文件不带路径,进程也知道。由此OS就能知道要创建的文件放在哪里。

3. 系统调用与文件I/O

打开文件的方式不仅仅是fopen,ifstream等流式,语言层的方案,其实系统才是打开文件最底层的方案。不过,在学习系统文件IO之前,先要了解下如何给函数传递标志位,该方法在系统文件IO接口中会使用到标志位

3.1标志位传递方法
复制代码
#include<stdio.h>
#define ONE_FALGE 1<<0
#define TWO_FALGE 1<<1
#define THR_FALGE 1<<2 
void Print(int falge)
{
   if(falge & ONE_FALGE)
   {
     printf("ONE_FALGE");
   }
   if(falge& TWO_FALGE)
   {
     printf("TWO_FALGE");
   }
   if(falge&THR_FALGE)
   {
    printf("THR_FALGE");
   }
 }
  int main()
 {
    Print(ONE_FALGE|TWO_FALGE);
    printf("\n");
    Print(ONE_FALGE|TWO_FALGE);
    printf("\n");
    Print(ONE_FALGE|TWO_FALGE|THR_FALGE);
    printf("\n");                                                                  
 }
3.2系统调用

除了C语言的标准库函数,文件操作也可以通过系统调用(如 open(), write(), read())直接与操作系统交互。这些系统调用是与内核直接交互的底层接口。

3.2.1open

常用标志位:

O_RDONLY:以只读方式打开文件。

O_WRONLY:以只写方式打开文件。

O_RDWR:以读写方式打开文件。

O_CREAT:如果文件不存在,则创建该文件。

O_APPEND:以追加模式打开文件。

O_TRUNC:如果文件已经存在,并且以写模式打开,则将文件的大小截断为零,丢弃文件的内容。

3.2.2权限掩码(umask)
复制代码
#include<stdio.h>
#include<sys/types.h>
#include<fcntl.h>
int main()
{
    int id=open("file",O_WRONLY|O_CREAT|O_APPEND,666);
    if(id<0)
    {
        perror("open\n");
    }
    return 0;
}

为什么会出现这样的情况?(我们设置文件权限为666但是实际权限只有664)

权限掩码:作用是控制文件和目录的访问权限,确保系统的安全性和资源的正确使用。在操作系统中,文件和目录通常会有不同的用户角色(如文件所有者、同一组用户和其他用户),每个角色可以对文件或目录执行不同的操作。权限掩码通过设置这些权限来定义哪些用户可以执行哪些操作。

文件掩码的权限会在创建文件时被隐藏。

在程序中定义权限掩码:

umask函数

将权限掩码设置为0:

复制代码
#include<stdio.h>
#include<sys/types.h>
#include<fcntl.h>
#include<sys/stat.h>
int main()
{
    umask(0);
    int id=open("file",O_WRONLY|O_CREAT|O_APPEND,666);
    if(id<0)
    {
        perror("open\n");
    }
    return 0;
}
3.3文件描述符

通过 open() 返回的文件描述符(一个小整数)管理打开的文件。每个进程有自己的文件描述符表。

此时的open返回值就是file文件的描述符:

3.3.1操作系统

通过这张表我们可以清楚认识到,所谓的C/C++中的文件操作的函数本质上都是对系统接口函数的封装。

3.3.2默认文件描述符0&1&2
复制代码
#include<stdio.h>
#include<sys/types.h>
#include<fcntl.h>
#include<sys/stat.h>
int main()
{
    umask(0);
    int id1=open("file1",O_WRONLY|O_CREAT|O_APPEND,0666);
    int id2=open("file2",O_WRONLY|O_CREAT|O_APPEND,0666);
    int id3=open("file3",O_WRONLY|O_CREAT|O_APPEND,0666);
    printf("%d\n",id1);
    printf("%d\n",id2);
    printf("%d\n",id3);
    return 0;
}

Linux默认会打开三个文件描述符分别是0,1,2

  • 0:标准输入 1:标准输出 2:标准错误
  • 他们对应的物理设备分别为:键盘,显示器,显示器
3.3.3文件描述符的分配规则

文件描述符的分配规则:在files_struct数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符。

|-----------|-----------|-----------|
| 操作: | 默认打开0,1,2 | 关闭文件描述符:0 |
| 打开的文件描述符: | 3,4,5 | 0,3,4 |
| 结论: | 在files_struct数组当中,找到当前没有被使用的最小的一个下标,作为新的文件描述符。 ||

3.4重定向

通过关闭标准输出 (stdout,文件描述符 1) 并将其指向文件,可以实现输出重定向,常见的有 >(输出重定向)和 <(输入重定向)。

重定向简单原理:

复制代码
#include<stdio.h>
#include<sys/types.h>
#include<fcntl.h>
#include<sys/stat.h>
#include<stdlib.h>
int main()
{
    close(1);
    int id1=open("file1",O_WRONLY|O_CREAT|O_APPEND,0666);
    int id2=open("file2",O_WRONLY|O_CREAT|O_APPEND,0666);
    int id3=open("file3",O_WRONLY|O_CREAT|O_APPEND,0666);
    printf("%d\n",id1);
    printf("%d\n",id2);
    printf("%d\n",id3);
    return 0;
}

当默认的标准输出流被关闭时,file1 会占据文件描述符 1(标准输出)。此时,printf 使用文件描述符 1 来确定输出目标,因此其输出会被写入到 file1 中。

解释: 重定向的原理是通过修改文件描述符的指向,使其指向新的文件或设备,从而改变程序的输出路径。

相关推荐
wkj0012 分钟前
QuaggaJS 配置参数详解
java·linux·服务器·javascript·quaggajs
不怎么爱学习的dan3 分钟前
实现 ECharts 多国地区可视化方案
前端
嘉小华3 分钟前
Android Lifecycle 状态同步与分发机制深度解析
前端
李三岁_foucsli9 分钟前
chrome架构-多进程和进程中的线程
前端·google
阿琳a_13 分钟前
前端对WebSocket进行封装,并建立心跳监测
前端·javascript·vue.js·websocket
Am1nnn18 分钟前
【Pinia】Pinia和Vuex对比
前端·javascript·vue.js
可爱小仙子22 分钟前
ios苹果系统,js 滑动屏幕、锚定无效
前端·javascript·ios
大得36925 分钟前
react菜单,动态绑定点击事件,菜单分离出去单独的js文件,Ant框架
前端·javascript·react.js
段旭涛31 分钟前
uniapp 设置手机不息屏
前端·uni-app
古夕33 分钟前
Promise A+ 规范解读
前端·javascript