基础IO(1)

1. 理解"文件"

1-1 狭义理解

  • 文件在磁盘里
  • 磁盘是永久性存储介质,因此文件在磁盘上的存储是永久性的
  • 磁盘是外设(即是输出设备也是输入设备)
  • 磁盘上的文件 本质是对文件的所有操作,都是对外设的输入和输出 简称 IO

1-2 广义理解

  • Linux下⼀切皆文件(键盘、显示器、网卡、磁盘...... 这些都是抽象化的过程)

1-3 文件操作的归类认知

  • 对于 0KB 的空文件是占用磁盘空间的
  • 文件是文件属性(元数据)和文件内容的集合(文件 = 属性(元数据) + 内容)
  • 所有的文件操作本质是文件内容操作和文件属性操作

1-4 系统角度

  • 对文件的操作本质是进程对文件的操作
  • 磁盘的管理者是操作系统
  • 文件的读写本质不是通过C语言/C++的库函数来操作的(这些库函数只是为用户提供方便),而是通过文件相关的系统调用接口来实现的

2 自我梳理

一、文件的本质定义

文件 = 文件内容 + 文件属性(元数据)

  • 后续所有文件操作,本质上就分为两类:
    1. 对文件内容的读写 / 修改
    2. 对文件属性的修改(如权限、大小、时间戳等)

二、文件访问的前提:路径与打开操作

  1. 访问文件必须先 "打开"

    • 打开文件是程序运行过程中,由进程 通过 fopen 动态完成的操作,不是静态行为。
    • 进程是文件操作的主体,理解进程与文件的关系是核心。
  2. 文件路径的本质:绝对路径 vs 相对路径

    • 访问文件必须依赖路径 + 文件名,没有 "无路径" 的访问方式。
    • 代码中写 fopen("log.txt", "w"); 这种不带路径的写法,不是不需要路径,而是默认使用 ** 进程的当前工作目录(CWD,Current Working Directory)** 作为路径,最终等价于 CWD/log.txt
    • 进程会动态维护自己的当前工作目录,可以通过 chdir 系统调用修改。

三、打开文件的本质:从磁盘到内存

  1. 磁盘文件的特性

    • 磁盘是永久性存储介质,文件在磁盘上是持久化存储的;同时磁盘是外设(兼具输入 / 输出功能),因此文件操作本质上是对磁盘的 IO 操作。
  2. 打开文件的核心行为

    • 打开文件的过程,是将磁盘上的文件(包括内容和属性)加载到内存中。
    • 后续所有对文件的读写操作,本质上都是进程通过 CPU 访问内存中的文件副本,再由操作系统同步到磁盘。

四、核心结论总结

  1. 文件操作的本质,是进程通过 IO 对磁盘文件的内容属性进行读写。
  2. 任何文件访问都依赖路径,相对路径的本质是使用进程的当前工作目录。
  3. 打开文件的过程,是将磁盘文件加载到内存,后续操作都是基于内存副本完成的。

3 文件操作

一、C 语言视角:文件操作与标准流

  1. stdin/stdout/stderr 是什么?

    • 它们是 C 语言标准库中预定义的 FILE* 指针,分别对应:
      • stdin:标准输入(键盘,文件描述符 fd=0
      • stdout:标准输出(显示器,文件描述符 fd=1
      • stderr:标准错误(显示器,文件描述符 fd=2
    • 所有 C 语言文件操作函数(如 fputsfwrite),最终都要通过 FILE* stream 参数指定操作的目标文件流。
  2. 库函数 vs 系统调用

    • 标准库函数(fopen/fclose/fread/fwrite/fflush)是对 Linux 系统调用(open/close/read/write)的封装。
    • FILE 结构体内部会持有文件描述符 fd 和缓冲区(如 hellobit),实现带缓冲的 IO。

二、内核视角:进程与打开文件的管理

  1. 文件描述符表(fd_array

    • 每个进程的 task_struct 中,都有一个 files_struct,它维护了一张文件描述符表 fd_array
    • 表中的每个索引(如 0、1、2、3...)就是文件描述符 fd,指向内核中的 struct file 对象。
    • fd=0/1/2 默认分别指向标准输入、输出、错误流,用户自己打开的文件会从 fd=3 开始分配。
  2. struct file:内核文件对象

    • 内核为每个打开的文件创建一个 struct file 实例,包含文件的状态信息(如文件位置指针、权限、引用计数等)。
    • 不同进程打开同一个文件时,会各自创建独立的 struct file,但它们最终会指向同一个磁盘文件的 inode(文件元数据)。

三、文件操作的本质流程

  1. 从磁盘到内存:文件操作的前提

    • 磁盘文件是持久化存储的,文件操作(读写)前必须先把文件加载到内存(内核缓冲区 / 用户缓冲区)。
    • 磁盘文件 = 文件属性(元数据,存在 inode 中) + 文件内容(数据块)。
  2. 用户态 ↔ 内核态 ↔ 磁盘 的数据流向

    • 用户调用 C 库函数(如 printf)→ FILE 缓冲区 → 系统调用(write)→ 内核缓冲区 → 最终刷写到磁盘。
    • 直接使用系统调用(write)没有用户态缓冲区,而 C 库函数带缓冲,效率更高。

四、关键问题与补充知识点

  1. 为什么 C 语言要封装系统调用?

    • 跨平台性 :不同操作系统的系统调用接口不兼容(如 Linux 的write和 Windows 的WriteFile),C 标准库屏蔽了底层差异,实现 "一次编写,到处运行"。
    • 缓冲优化:用户态缓冲减少了系统调用次数,大幅提升 IO 效率。
  2. FILE 结构体与 fd 的关系

    • FILE 是 C 库提供的用户态句柄,它的成员中包含了内核的文件描述符 fd,以及用户态缓冲区、标志位等信息。
    • 调用 fopen 时,C 库会先调用 open 系统调用拿到 fd,再初始化一个 FILE 对象;fclose 则会刷新缓冲区并调用 close 系统调用。
  3. C++ 文件流的补充

    • C++ 的 ifstream/ofstream 也是对底层文件操作的封装,和 C 库的 FILE 类似,同样基于文件描述符和缓冲机制。

五、核心结论总结

  1. 用户态的文件操作(C 库 / C++ 流),本质上都是通过文件描述符,间接操作内核中的文件对象,最终访问磁盘文件。
  2. 文件描述符 fd 是进程与内核文件对象的桥梁,FILE 是 C 库为了实现跨平台和缓冲优化,在用户态封装的一层。
  3. 打开文件的本质,是内核为进程创建文件对象、分配文件描述符,并建立进程与磁盘文件的关联。
相关推荐
鹏大师运维4 小时前
为什么信创电脑装软件总提示“软件包架构不匹配”?
linux·运维·架构·国产化·麒麟·deb·统信uos
007张三丰5 小时前
软件测试专栏(11/20):测试框架开发:pytest深度解析与插件体系
运维·服务器·自动化测试·pytest·测试框架
海南java第二人5 小时前
Nebula Graph 实战:基于图数据库存储 CMDB 实体关系
数据库·图数据库·nebula
weixin_604236676 小时前
华三 路由器 极简核心配置
运维·服务器·网络·h3c·h3c路由器
曹牧6 小时前
oracle:“not all variables bound”
数据库·oracle
数据库百宝箱6 小时前
Oracle RMAN Image Copy 本地恢复
数据库·oracle
鹤落晴春6 小时前
【Linux复习】管理SELinux安全性
linux·运维·服务器
yz_aiks6 小时前
Linux Jar包配置Systemd自启动实战:从排查到配置全流程
linux·python·jar·自启动·systemd
AI智图坊7 小时前
多件装组合SKU图的批量生产效率分析:从PS手工到AI自动化的工作流改造
大数据·运维·人工智能·gpt·ai作画·自动化·aigc
zuYM4g7Dp7 小时前
NoSql数据库设计心得
数据库·nosql