操作系统之系统IO

发布于:2025-04-17 ⋅ 阅读:(17) ⋅ 点赞:(0)

🌟 各位看官好,我是maomi_9526

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

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

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

目录

1. 文件的概念

2. C语言文件操作接口

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 中。

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


网站公告

今日签到

点亮在社区的每一天
去签到