目录
[1. 背景补充](#1. 背景补充)
[2. 理解"文件"](#2. 理解“文件”)
[2.1 狭义理解](#2.1 狭义理解)
[2.2 广义理解](#2.2 广义理解)
[2.3 文件操作的归类认知](#2.3 文件操作的归类认知)
[2.4 系统角度](#2.4 系统角度)
[3. 复习C文件接口](#3. 复习C文件接口)
[3.1 以 C语言"w" 方式打开文件:](#3.1 以 C语言“w” 方式打开文件:)
[3.1.1 实现清空文件的操作](#3.1.1 实现清空文件的操作)
[3.2 以 C语言"a" 方式打开文件:](#3.2 以 C语言“a” 方式打开文件:)
[3.3 实现cat命令](#3.3 实现cat命令)
[3.4 系统](#3.4 系统)
[3.5 输出信息到显示器,你有哪些方法](#3.5 输出信息到显示器,你有哪些方法)
[4. 库文件操作和系统调用](#4. 库文件操作和系统调用)
[编辑4.1 用系统调用实现 "w" 的方式](#编辑4.1 用系统调用实现 "w" 的方式)
[4.2 用系统调用实现"a"的方式](#4.2 用系统调用实现"a"的方式)
[4.3 结论](#4.3 结论)
[4.4 open()返回值:文件描述符](#4.4 open()返回值:文件描述符)
基础IO:重点理解文件相关的内容!!!
1. 背景补充

2. 理解"文件"
2.1 狭义理解
- 文件在磁盘里
- 磁盘是永久性存储介质,因此文件在磁盘上的存储是永久性的
- 磁盘是外设(即是输出设备也是输入设备)
- 磁盘上的文件本质是对文件的所有操作,都是对外设的输⼊和输出 简称 IO
2.2 广义理解
Linux 下⼀切皆是文件(键盘、显示器、网卡、磁盘...... 这些都是抽象化的过程)(后面文章会提如何去理解)
2.3 文件操作的归类认知
- 对于 0KB 的空文件是占用磁盘空间的
- 文件是文件属性(元数据)和文件内容的集合(文件= 属性(元数据)+ 内容)
- 所有的文件操作本质是文件内容操作和文件属性操作
2.4 系统角度
- 对文件的操作本质是进程对文件的操作
- 磁盘的管理者是操作系统
- 文件的读写本质不是通过 C 语言 / C++ 的库函数来操作的(这些库函数只是为用户提供方便),而是通过文件相关的系统调用接口来实现的
3. 复习C文件接口

运行结果:


但是当我们修改了当前工作路径的话,文件就会被建在新的指定的路径下,哪又该如何修改文件的路径呢?
使用 chdir 命令:



此时进程对应的当前工作路径改变了:


所以打开文件本质是:进程在打开。所以:
打开文件,必须要找到文件,要找到文件,就必须知道该文件的路径+文件名,这就是为什么进程要有cwd的原因之一!!!所以cwd是查找文件的默认路径!!所以:#include<>查头文件,是在系统的路径下找,找不到再到当前的路径下找;#include " " 默认在当前的路径下找,编译器会帮忙找的,因为编译器跑起来是一个进程。因为编译器也有自己的cwd,所以#include " " 默认在当前的路径下找。
在打开文件时,任何时候,只有文件名打开文件,当前都会有路径,因为进程会自动记录下来。同样在vs中,编译的时候启动编译器,编译器就是一个进程,有进程就有当前路径,有当前路径就能在当前路径下找头文件。
3.1 以 C语言"w" 方式打开文件:

运行结果:

多次运行结果一直不变:

在 log.txt 文件中手动写入一些内容:


原来的文件的内容变短了。

3.1.1 实现清空文件的操作
那么想写一个进行清空文件的软件应该如何写呢?

上述代码,实现将文件打开,在关闭就实现了自动清空的功能。

3.2 以 C语言"a" 方式打开文件:



3.3 实现cat命令





在文件中加了一些内容:

再次查看log.txt文件:

所以cat命令在打印一个文件的时候,如何将文件的内容打印出来的呢?
cat log.txt 的时候,cat 命令就有命令行参数将对应的log.txt传到cat进程里面了,之后cat命令在shell当中就会创建子进程,父进程fork之后exec让cat将文件打开,进行打印。
3.4 系统

3.5 输出信息到显示器,你有哪些方法

写二进制就直接往文件中写入,写文本类文件是要进行格式化输入输出的,显示器和键盘进行读写只认字符,读进来的是字符转换成整数,输出的时候是字符转换成整数再打印,这就是格式化输入和输出。打印字符串的话,字符串本身就不用转换了,显示器和键盘都认为是一个一个的字符,所以计算机中才有一张表结构:ASCII码表,ASCII码表是数字和图形的关系,printf转为字符'1''2''3''4''5'之后,1字符就是一个整数,在查对应的ASCII码表,就可以得到1字符的显示的格式,显示器在查找ASCII码表,再将ASCII码表中的1字符显示出来。汉字、中英文也好都是符号。
显示器读写其实是文本读写。



想向显示器文件打印字符串:


运行结果:

以上接口都可以向显示器中显示。
所以真正的打开文件,调用的不是C语言的接口:fopen,而是fopen底层封装的open()系统调用来打开文件。
4. 库文件操作和系统调用



运行结果:

4.1 用系统调用实现 "w" 的方式

运行结果,返回的是没有此文件或目录

以写的方式打开文件时,文件不存在时,是会创建一个新的文件,没错,但那是C语言。我们使用 O_WRONLY 发现文件新建不了,如果要新建一个不存在的文件时,加上 O_CREAT。


但是可以看见 log.txt 的权限是乱码,这是要指明该新建文件的权限是多少:


可以看见我们设置的权限是666,但是显示出来的 log.txt 文件权限是664,因为系统中存在umask,umask会限制掉对应的权限,把other的写去掉了。

但是我们非得创建出一个权限为666的文件,如何操作?



同时,umask是不受影响的:

在代码中新建文件,设置权限时,所使用的掩码就近原则,如果用户设置了umask就合权限进行权限运算,如果没有设置权限就采用系统的umask。
系统调用有点像C语言,用系统调用也可以向文件写入:





log.txt 文件没有清空,而是将里面的内容能够覆盖多少就覆盖多少,C语言中是清空了的,但是系统调用默认是没有清空的。我们想将文件内容进行清空呢?



此时,如果我们只进行打开文件,关闭文件的操作,不做写入的话,就会达到将文件清空的作用。

运行结果:


4.2 用系统调用实现"a"的方式
追加方式打开文件,文件不存在,也会帮我们新建文件:



4.3 结论
由 4.1 和 4.2 得到的结论:


4.4 open()返回值:文件描述符

open() 返回的是整数。



运行结果:

上面的 3、4、5、6代表的是什么?

所以 3、4、5、6代表的是数组的下标,所以 write(fd,...) 和 close(fd,...)必须得传递文件描述符,上面的图属于OS内部,在OS内部,OS识别被打开的文件,OS只认:fd

