一、理解文件
1、1-1、狭义理解
在侠义上,文件就是存储在磁盘等介质上的数据集合,比如.txt、.c、.jpg。等
特点是:有文件名、有大小、有内容、是我们最直观接触到的文件形式。
2、1-2、广义理解:
Linux的核心思想是:Linux下一切皆文件,在Linux系统中,几乎所有的资源都被抽象成文件。
包括:普通文件、目录、设备(键盘、显示器、磁盘、网卡)、管道、套接字(socket)等
好处:
统一了操作接口,对设备的读写就像对普通文件的读写一样。
文件=文件的内容+文件的属性(元数据)
1-3、文件操作的归类认知
1、打开(open):建立进程与文件的链接,获取操作句柄。
2、读写(read/weite):从文件中读取数据,或向文件写入数据。
3、定位(seek):移动文件内部的读写位置指针。
4、关闭(close):断开进程与文件的连接,释放资源。
1-4、系统角度
从操作系统视角看,文件是一个被管理的对象,有对应的元数据(如:权限、大小、创建时间)
进程通过文件描述符(File Descriptor)来引用和操作这些文件对象。
Fopen
访问为文件之前,必须先打开文件,用fopen,用完再用close,动态的打开,文件是一个动态被打开的过程(程序跑起来之后,临时做的fopen就是典型的动态打开),不是编译时打开,而是运行时才打开。
打开文件就是进程在打开文件,因为是动态打开的,程序跑起来,就是进程;所以是进程打开文件的,研究文件和程序的关系,本质是研究进程和文件的关系。
路径
访问任何文件,必须要有路径要么用户自己提供要么用户使用进程的cwd
二、回顾c文件接口
2-1 、输出信息到显示器的方法
1、printf();格式化输出到标准输出(stdout)
2、puts():输出字符串并自动换行
3、putchar():输出单个字符
4、fprintf(stdout,...):等价于printf(),显式指定输出到stdout
5、write(1,...):使用系统调用直接向文件描述符(stdout)写入。
2-2、stdin 、 stdout、 stderr
1、标准输入(stdin):文件描述符为0,默认是键盘、用于读取数据
2、标准输出(stdout):文件描述符是1,默认是显示器,用于输出正常信息
3、标准错误(stderr):文件描述符为2,默认是显示器,用于输出错误信息
在c语言中,他们是三个预定义的FILE* 指针:stdin、stdout、stderr
重定向的本质就是改变着三个流的指向。例如:command> output.txt就是将stdout重定向到文件。
|----|-----|--------|-------|------|------------|
| 模式 | 含义 | 文件不存在时 | 文件存在时 | 初始位置 | 读写限制 |
| r | 只读 | 报错 | 打开 | 文件开头 | 只能读 |
| r+ | 读写 | 报错 | 打开 | 文件开头 | 可读可写 |
| w | 只写 | 创建新文件 | 清空内容 | 文件开头 | 只能写 |
| w+ | 读写 | 创建新文件 | 清空内容 | 文件开头 | 可读可写 |
| a | 追加 | 创建新文件 | 打开 | 文件末尾 | 只能写且只能追加 |
| a+ | 读追加 | 创建新文件 | 打开 | 文件末尾 | 读从开头,写总是追加 |
问题1:打开文件,就是把文件加载到内存?
不是。fopen只是"建立连接,登记信息",文件内存还在硬盘里,根本没进内存。 打开文件=办个手续,不是把东西搬进来。只有调用读/写函数时,才加载。
文件的分类
Linux存在大量文件,分为打开的和没有被打开的,文件从位置上:1、内存级被打开的文件和没有被打开的。
文件从位置上,1、内存级被打开的文件 2、磁盘文件
Linux中,可以存在很多被打开的文件!
os如何管理这些文件呢?
三、Linux进行文件操作
1、打开文件open
open和它的参数介绍


运行结果:由于打开的这个文件不存在,所以要新建文件,但是新建文件需要设置文件权限,用第二个open。

所以必须对源文件进行修改:

结果是:

但是这个log.txt的权限是乱码,所以必须给它设置权限,此时就需要open的第三个参数
如下图:

此时他的权限就是正常的,如下:

但是这里的权限为什么是664呢?

那些因为在Linux系统里,里面会有umask权限掩码,它是002(八进制)--->000 000 010(二进制),权限666减去umask掩码002就是664.
此时可以改写系统的Umask掩码 如下:


再来看运行结果:这下权限都是可读可写权限了

umask
那么我们自己设置了umask掩码,系统里面也有umask掩码

2、关闭文件close


close使用方法

3、向文件描述符写write


open...库函数封装系统调用=内核不让你进,给你一层"安全外套"
O_TRUNC
你这里的 O_TRUNC 是 Linux 系统调用 open() 的一个标志位,,是 O_TRUNC(Truncate 的缩写)。
它的作用是:
-
如果要打开的文件已经存在,并且是以只写或读写方式打开的,那么 O_TRUNC 会把文件的原有内容全部清空(截断为 0 字节),然后再写入新内容。
-
如果文件不存在,这个标志位就没有效果。
简单来说, O_TRUNC 就是"清空重写"的意思,确保写入的内容是全新的,而不是追加到旧内容后面。
open() 常用标志位(如 O_RDONLY , O_WRONLY , O_CREAT , O_APPEND 等)

于是呢,我们就成功的将数据写进去了

此时,log.txt的内容是;

我们修改写入文件的内容:

在编译之前log.txt是有老内容的。如下图

在让这个文件运行。结果会从上次结果的开始进行覆盖式的。

修改:

之后重新编译运行,结果是:

O_APPEND

O_APPEND = 追加模式
-
写文件时,永远从文件末尾写
-
不会覆盖原来的内容,只在后面加
我们直接看效果:这就是追加后的结果

问题:这里的fd为什么是3呢?

答:在 Linux 中,每个进程启动时,系统会自动打开 3 个标准文件描述符:
-
0 :标准输入(stdin)
-
1 :标准输出(stdout)
-
2 :标准错误(stderr)
当程序调用 open() 打开新文件时,内核会分配当前最小的未被使用的整数作为文件描述符。因为 0、1、2 已被占用,所以第一个新打开的文件,其文件描述符就是 3。
你看到的 fd: 3 ,就是程序中新打开文件的文件描述符。
库函数封装了系统调用
write(1,msg,strlen(msg)),1代表标准输出, msg指的是输出内容的指向。

运行结果:

问题:文件描述符的本质是什么?
答:数组下标

为什么要c封装,理解一下C的IO函数。
答**:你的程序
↑↓ (用 fopen / fread / fwrite / printf)
struct FILE (封装层:缓冲区、状态、方便操作)
↑↓ (真正干活:open / read / write)
操作系统内核(文件描述符 0 1 2 3...)**
C 语言 IO 总结
- 系统调用:open / read / write
-
用 数字 fd(0、1、2、3...)
-
直接跟操作系统打交道
-
无缓冲、麻烦、效率低、只能读写字节
- C 标准库:FILE / fopen / printf / fread*
-
是对上面系统调用的 封装
-
用 FILE 结构体 * 管理一个文件(文件流)
-
自带 缓冲区,速度快
-
能格式化、按行、跨平台、好用
- 关系(最重要)
-
stdin / stdout / stderr 是 FILE*,不是数字
-
fileno(fp) 能从 FILE* 拿到 fd 数字
-
封装 = 为了让你写代码更简单、更快、更安全
系统调用玩数字 fd,C 库玩 FILE 封装。
c封装好处
1. 有缓冲区,速度更快
不用每写一个字节就调用系统,减少开销。
2. 功能更强
能 printf 格式化、 fgets 按行读、 fscanf 解析数据。
3. 跨平台
Windows、Linux、mac 都能用同一套代码。
4. 更简单、更安全
自动帮你管错误、文件位置、状态,不用自己写底层。
为什么语言要有很好的跨平台性?
为了有更多的用户。