当前位置: 首页 > news >正文

重庆市建设工程施工安全管理总站优化新十条

重庆市建设工程施工安全管理总站,优化新十条,动易手机网站,潮州网站建设文章目录 前言lesson 15_基础IO一、共识原理二、回顾C语言接口2.1 文件的打开操作2.2 文件的读取与写入操作2.3 三个标准输入输出流 三、过渡到系统,认识文件系统调用3.1 open 系统调用1. 比特位标志位示例 3.2 write 系统调用1. 模拟实现 w 选项2. 模拟实现 a 选项…

在这里插入图片描述

文章目录

  • 前言
  • lesson 15_基础IO
    • 一、共识原理
    • 二、回顾C语言接口
      • 2.1 文件的打开操作
      • 2.2 文件的读取与写入操作
      • 2.3 三个标准输入输出流
    • 三、过渡到系统,认识文件系统调用
      • 3.1 `open` 系统调用
        • 1. 比特位标志位示例
      • 3.2 `write` 系统调用
        • 1. 模拟实现 `w` 选项
        • 2. 模拟实现 `a` 选项
      • 3.3 `read` 系统调用
    • 四、访问文件的本质
  • 结语


前言

本文将从文件的基本概念出发,先回顾 C 语言中文件操作的常用接口,再逐步过渡到 Linux 系统调用,解析文件描述符、文件打开对象、进程与文件的关系等关键概念。通过代码示例和原理分析,带你揭开 Linux 基础 IO 的神秘面纱,理解操作系统如何管理文件、进程如何与文件交互的底层逻辑。


lesson 15_基础IO

一、共识原理

  • 文件 = 内容 + 属性。

  • 文件分为 打开的文件没打开的文件

  • 打开的文件:谁打开的?进程!—— 本质是研究进程和文件的关系。

  • 没打开的文件:在哪里放着呢?在磁盘上。我们最关注的问题?没有被打开的文件非常多,文件如何被分门别类的放置好(如何存储) —— 我们要快速的进行增删查改 —— 快速找到文件。

  • 文件被打开,必须先被加载到内存!

  • 进程:打开的文件 = 1:n。

小结:操作系统内部,一定存在大量的别打开的文件!—— OS 要不要管理这些被打开的文件呢? —— 怎么管理???—— 先描述,在组织。—— 在内核中,一个被打开的文件都必须有自己的文件打开对象,包含文件的很多属性。struct XXX{文件属性;struct XXX *next};

二、回顾C语言接口

2.1 文件的打开操作

  • fopen 函数用于打开文件,格式为

    • FILE *fopen(const char *path, const char *mode);
      
    • path: 文件路径或文件名。如果只有文件名,操作系统会在当前工作目录(cwd)下查找该文件。

    • mode: 文件打开模式。常见模式有:

      • w: 如果文件已存在,先清空文件再写入。如果文件不存在,创建新文件。
      • a: 以追加模式打开文件,在文件末尾添加内容。
  • 当前路径 (cwd): 每个进程维护一个当前工作目录,操作系统会根据该目录来查找文件。如果路径没有指定,fopen 会使用进程的当前工作路径。

  • 2.2 文件的读取与写入操作

    • fwrite 用于向文件写入数据。其函数声明为:

      size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
      
      • ptr: 指向要写入数据的指针。
      • size: 每个写入对象的大小。
      • nmemb: 要写入的对象个数。
      • stream:文件流指针
    • 举例使用:

      int main()
      {FILE *fp = fopen("log.txt", "w");if (fp == NULL){perror("fopen");return errno;}char* str = "Hello Linux!";fwrite(str, strlen(str), 1, fp);fclose(fp);return 0;
      }
      
      • fwrite的第二个参数是指每个写入对象的大小,strlen函数返回的值是不包含字符串结束标识符,那么我们传参是加一还是不加一呢?加一就代表把\0写入到文件中,那么我们是应该怎么选择呢?这里不妨试一试加一的结果:

        注意 log.txt 文件中,字符串的末尾有一个^@,是什么意思呢?实际上这个字符组合是表示\0的ASCII码,所以写入字符串时,使用 strlen 计算字符串长度时,不包括结束符 \0。通常不需要将 \0 写入文件,因为它是 C 语言中的结束标志,而在其它语言中读取文件时,可能不希望看到这些无关的字符。

    2.3 三个标准输入输出流

    C 程序启动时,会自动打开以下三个标准流:

    • stdin: 标准输入流(通常与键盘连接)。
    • stdout: 标准输出流(通常与显示器连接)。
    • stderr: 标准错误流(通常与显示器连接)。

    这三个流都由操作系统和 C 标准库提供,并用于处理程序与外部交互的基本输入输出。

三、过渡到系统,认识文件系统调用

文件其实是在磁盘上的,磁盘是外部设备,访问磁盘文件其实是访问硬件!几乎所有的库只要是访问硬件设备,必定要封装系统调用。

3.1 open 系统调用

open 是一个用于打开文件或创建文件的系统调用,其原型为:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);
  • 参数说明
    • pathname: 文件路径。
    • flags: 打开文件时的标志,例如:
      • O_RDONLY:只读打开。
      • O_WRONLY:只写打开。
      • O_RDWR:读写打开。
      • O_CREAT:文件不存在时创建文件。
      • O_TRUNC:打开文件时清空文件内容。
      • O_APPEND:以追加模式打开文件。
    • mode: 在使用 O_CREAT 时,需要指定新文件的访问权限。
  • 返回值:成功返回文件描述符,失败返回 -1。
1. 比特位标志位示例

通过按位或(|)传递多个标志位,可以在同一次调用中同时指定多个选项。

代码示例:

#define ONE (1<<0) // 1
#define TWO (1<<1) // 2
#define FOUR (1<<2) // 4
#define EIGHT (1<<3) // 8void show(int flags)
{if(flags & ONE) printf("function1\n");if(flags & TWO) printf("function2\n");if(flags & FOUR) printf("function3\n");if(flags & EIGHT) printf("function4\n");return;
}int main()
{printf("--------------------------------------\n");show(ONE);printf("--------------------------------------\n");show(ONE | TWO);printf("--------------------------------------\n");show(ONE | TWO | FOUR );printf("--------------------------------------\n");show(ONE | TWO | FOUR | EIGHT);printf("--------------------------------------\n");return 0;
}

输出示例:

3.2 write 系统调用

write 用于将数据写入文件,其原型为:

ssize_t write(int fd, const void *buf, size_t count);
  • 参数说明:
    • fd: 文件描述符。
    • buf: 指向数据缓冲区的指针。
    • count: 要写入的数据字节数。
  • 返回值:实际写入的字节数。
1. 模拟实现 w 选项

模拟 fopenw 模式(清空文件后写入):

int main()
{umask(0); // 将权限掩码设置成0000int fd = open("log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666); if(fd < 0){printf("open file error\n");return 1;}const char* str = "bbb";ssize_t ret = write(fd, str, strlen(str));close(fd);return 0;
}
2. 模拟实现 a 选项

模拟 fopena 模式(追加写):

int main()
{umask(0); int fd = open("log.txt", O_WRONLY | O_CREAT | O_APPEND, 0666); if(fd < 0){printf("open file error\n");return errno;}const char* str = "bbb";ssize_t ret = write(fd, str, strlen(str));close(fd);return 0;
}

3.3 read 系统调用

read 用于从文件中读取数据,其原型为:

ssize_t read(int fd, void *buf, size_t count);
  • 参数说明
    • fd: 文件描述符。
    • buf: 存储读取数据的缓冲区。
    • count: 缓冲区的大小。
  • 返回值:实际读取的字节数。

四、访问文件的本质

  1. struct file 结构体的作用
  • 当文件被打开时,操作系统为该文件创建一个 struct file 结构体对象,负责管理该文件的元数据和访问信息。
  • 操作系统对文件的管理本质上就是对这些 struct file 结构体对象的管理,它们被组织成一个双链表,保存所有当前打开的文件。
  1. 文件描述符表(files_struct
  • 每个进程都有一个 struct files_struct 类型的对象,它记录了该进程所打开的所有文件的信息。
  • struct files_struct 中有一个文件描述符表,维护了一个 struct file* 类型的数组。数组的下标就是文件描述符,指向进程打开的文件的 struct file 结构体对象。
  1. 文件描述符的分配规则
  • 操作系统会为进程打开的新文件分配一个文件描述符,分配从 3 开始(因为标准输入、输出、错误流占用文件描述符 0、1、2)。
  • 新打开的文件将从进程的文件描述符表中找到最小的未使用下标,作为文件描述符。
  1. FILE 类型在 C 语言中的作用
  • FILE 是 C 语言库中的封装类型,用于描述文件,它提供了更高层次的文件操作接口。

  • FILE 类型内部封装了文件描述符,_fileno 字段就是对应的文件描述符,可以通过它来访问底层的文件描述符。

    int main()
    {umask(0); int fd1 = open("log1.txt", O_WRONLY | O_CREAT | O_APPEND, 0666); int fd2 = open("log2.txt", O_WRONLY | O_CREAT | O_APPEND, 0666);int fd3 = open("log3.txt", O_WRONLY | O_CREAT | O_APPEND, 0666);int fd4 = open("log4.txt", O_WRONLY | O_CREAT | O_APPEND, 0666);printf("fd1: %d\n", fd1);printf("fd2: %d\n", fd2);printf("fd3: %d\n", fd3);printf("fd4: %d\n", fd4);return 0;
    }
    
  1. 文件的引用计数与关闭
  • 文件可以被多个进程同时打开,struct file 中有一个 f_count 字段来记录文件的引用计数。
  • 当进程关闭文件时,close 系统调用会将文件描述符表中对应位置的内容置为 NULL,减少文件的引用计数。如果引用计数为 0,操作系统会回收该文件对应的资源。
  1. 标准输入、输出和错误流(文件描述符 0, 1, 2)
  • 操作系统会在程序启动时自动打开标准输入(文件描述符 0)、标准输出(文件描述符 1)和标准错误(文件描述符 2)。

  • 这三个文件描述符是预留的,程序中打开的新文件会从文件描述符 3 开始。

  1. 文件描述符的关闭与输出
  • 通过 close 系统调用关闭文件描述符后,进程无法再通过该文件描述符进行文件操作。例如,关闭标准输出(close(1))会导致后续的 printf 输出无法显示,但其他流如标准错误仍然有效。

    int main()
    {close(1); // 将 stdout 关闭int ret = printf("stdin->fd: %d\n", stdin->_fileno);printf("stdout->fd: %d\n", stdout->_fileno);printf("stderr->fd: %d\n", stderr->_fileno);fprintf(stderr, "printf ret: %d\n", ret);return 0;
    }
    

结语

IO 操作是操作系统的 “血脉”,理解其底层原理不仅能帮助我们写出更健壮的代码,还能为深入学习进程通信、网络编程等高级主题奠定基础。希望本文能成为你探索 Linux 系统编程的一块基石,在后续的学习中,你可以尝试结合实际项目,对比不同 IO 接口的性能差异,或深入分析内核源码中的文件管理逻辑,进一步提升技术深度。

今天的分享到这里就结束啦!如果觉得文章还不错的话,可以三连支持一下,17的主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的支持就是17前进的动力!

在这里插入图片描述

http://www.cadmedia.cn/news/10621.html

相关文章:

  • 网站建设与网页设计作业seo有哪些优化工具
  • 浙江建设三类人员证书查询成都优化网站哪家公司好
  • 海东网站建设公司北京seoqq群
  • 网页设计包含的内容网站优化师
  • 建立网站还是建设网站想做电商怎么入手
  • 知名的网站建设百度seo软件
  • 三屏网站建设seo在线优化技术
  • 政府网站内容建设 投标重庆排名seo公司
  • 苏州营销网站建设公司排名培训机构营业执照如何办理
  • 聊城专业网站开发公司seo推广优化公司哪家好
  • 北京网站建设升上去济南专业做网站
  • 做网站建设的怎么赢利搜索引擎优化的常用方法
  • 阳江房产网签查询seo网站推广如何做
  • 中恒建设职业技术培训学校网站推广怎么推
  • 荥阳市建设局 网站安卓优化大师老版本下载
  • 政务网站建设的功能模块东莞百度快速优化排名
  • 芗城网站建设苏州seo网站管理
  • 网站开发的公司排名如何优化搜索引擎的搜索功能
  • 装饰设计培训网络seo推广
  • 学校网站 建设措施百度推广电话销售好做吗
  • 建设银行网站无法打开seo技术网
  • wordpress数据连接信息百度网站优化软件
  • 备案期间关闭网站排名优化seo公司
  • 安徽网站建设维护百度站长快速收录
  • 土木工程网官网首页佛山百度关键词seo外包
  • 湛江宇锋网站建设长沙seo推广公司
  • 龙岩市住房与城乡建设部网站重庆森林为什么不能看
  • 网络推广的几种主要方法成都seo技术
  • 做网站要固定电话百度推广一个月多少钱
  • 广东建设安全员报名网站网络营销推广公司名称