基础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. 打开文件的本质,是内核为进程创建文件对象、分配文件描述符,并建立进程与磁盘文件的关联。
相关推荐
vortex52 小时前
守护开源世界的猎犬:ClamAV 软件包介绍
linux·网络安全
zzzb1234562 小时前
WSL(Ubuntu)部署Nginx\+PHP8\.2完整教程(新手友好\+避坑指南)
linux·nginx·ubuntu·php
2403_883261092 小时前
SQL视图数据不实时怎么办_利用SQL触发器与视图联动方案
jvm·数据库·python
m0_684501982 小时前
如何利用 watchEffect 实现在线人数实时统计?Socket 与响应式结合
jvm·数据库·python
zhangchaoxies2 小时前
C#怎么使用全局Using C#global using全局引用怎么配置减少每个文件的using声明【语法】
jvm·数据库·python
neo33012 小时前
debian MEDIATEK Corp. Device 7925 无线网卡驱动安装
运维·服务器·debian
m0_676544382 小时前
mysql执行预处理语句流程是怎样的_SQL执行优化解析
jvm·数据库·python
aXin_ya2 小时前
微服务(高级) 8
java·数据库·微服务
zxrhhm2 小时前
Oracle 19c RAC 默认表空间类型的管理及总结
数据库·oracle