CSAPP Chapter 10 System-Level I/O 学习笔记(不定期更新)
学习进度
- 10.1 Unix I/O
- 10.2 Files
10.1 Unix I/O
学习契机
在学习CSAPP第11章的socket套接字接口的时候,在介绍相关的方法时,提到了大量的 file descriptor
的参数,发现这个概念有点陌生了,就来复习巩固一下。这么说来我对于各种语言的文件读写一直都有一种望而却步能用就行的感觉,没有好好的学习使用过,从Unix I/O开始也可以打下一个良好的基础。
什么是I/O
I/O就是Input和Output,是对于 main memory
主存与 external devices
外部设备(e.g., 硬盘,终端以及网络)之间数据的输入与输出:
- Input:将数据从从I/O设备中拷贝到主存中
- Output:将数据从内存中拷贝到外部设备上
Unix中的I/O
关于Unix中I/O的具体实现,首先我们要了解的两个很重要的结论:
- 在Unix中,所有的I/O设备都是以
文件
的形式存储和操作 - 那么所有这些I/O操作都是通过读写这些文件来实现的
其中,Wikipedia对于I/O 设备的定义如下: “I/O devices are the pieces of hardware used by a human (or other system) to communicate with a computer … Devices for communication between computers, such as modems and network cards, typically perform both input and output operations.”
了解到了这两点之后, 所有
的I/O操作就可以规范地定义为对于 文件
的几个规范性操作,也就是Interface接口:
- Opening files, 打开文件
- 触发:当一个应用想要访问操作一个I/O设备(想要输入或者输出)的时候,就会要求kernel去打开对应的代表I/O设备的文件
- 结果:Kernel内核会返回一个很小的正整数,我们叫做
descriptor
描述符,用来在之后对于该I/O设备文件的所有操作中,唯一标识该文件 - Kernel内核会持续跟踪该打开文件的所有的信息;而应用只会跟踪返回的
descriptor
描述符 - 每一个运行的进程会由Linux shell通过打开三个文件开启(个人认为就是启动一个进程需要用到三种I/O设备,因此开启了这三个文件,并返回了三个描述符):
- standard input (descriptor 0) 标准输入
- standard output (descriptor 1) 标准输出
- standard error (descriptor 2) 标准错误
- Changing the current file position 改变当前文件(内容)位置
- File position文件位置表示文件中下一个将要被读写的字符的位置
- Kernel会维护每一个打开的文件的file position
k
- k的初始值为0,每次有字符的读写,file position都会自增
- 应用也可以通过
seek
操作来显示地修改file position
- Reading and writing files 读写文件
- Read 读文件:从一个文件中读取n bytes的数据,从该文件当前的file position k开始读,并且递增n
- 如果读文件超过文件的size m,则会触发
end-of-file (EOF)
, 值得注意的是,这是由应用自动检测到的,而不是真的有一个字符叫做EOF符
- 如果读文件超过文件的size m,则会触发
- Write 写文件,同样也会递增file position k文件位置
- Read 读文件:从一个文件中读取n bytes的数据,从该文件当前的file position k开始读,并且递增n
- Closing files 关闭文件
- 触发:当应用结束访问一个文件的时候,就会要求kernel去
close
关闭这个文件 - 结果:kernel会释放所有的所有该文件创建的数据结构;并且将该文件的
descriptor
描述符归还到可用的描述符池中去 - 当一个进程结束时,kernel会关闭所有打开的文件并且释放他们的内存资源,比如之前提到的标准输入/输出/错误文件,都会被关闭
- 触发:当应用结束访问一个文件的时候,就会要求kernel去
10.2 Files 文件
学习契机
跟随10.1顺便看看
文件分类
Linux中对于不同的文件都有其所对应的分类
- regular file 常规文件
- 一个普通文件中可以包含任意数据,根据内容存储形式的不同,我们还可以再细化为:
-
text files, 文本文件,即只包含ASCII或者Unicode字符的文件
-
其中文本文件包含一串
text lines
文件行,每一行都由newline
符号'\n'
结尾(Linux, Mac OSX) -
再Ms Windows以及Internet协议例如HTTP中,则是使用
'\r\n'
(0xd 0xa)表示的 -
因此当我们在Linux以及Mac OSX环境下阅读由MS Windows编辑的文本文件时,每行后面都会出现 ‘^M’,可以使用一下命令来进行清理
linux> perl -pi -e "s/\r\n/\n/g" foo.txt
-
-
binary files,二进制文件,
-
- directory 目录
-
目录时一个包含一组
links
链接的文件,每一个链接都对应一个文件(常规文件或者目录) -
每一个目录文件至少包含两个默认链接
- . (dot), 该链接指向该目录文件本身
- .. (dot-dot),该链接指向
parent directory
mkdir
创建目录文件,ls
查看内容,rmdir
删除目录
-
- socket 套接字
- 套接字文件用来与其他进程进行网络通信(详见11.4)
文件目录结构
Linux内核通过唯一一个目录结构来管理所有的文件,该结构是由 root directory
根目录开始的一个树状结构,用 /
来表示,因此我们在一个文件路径中开头看到 /
要知道,这是一个目录文件,和后面使用到的 /
用作分隔符的概念时不一样的
Figure 1: Linux目录结构
每一个进程都有一个 current working directory
用来表示其在这个目录结构中的位置,通过 cd
命令可以改变shell的 current working directory
那么对应Linux目录结构,有两种形式来表达一个文件的位置(Location):
- Absolute pathname, 绝对路径,表示从根目录(/)开始的路径(之后的/表示路径的分割),例如上图中的hello.c文件的绝对路径就是/home/droh/hello.c
- Relative pathname,相对路径,表示从一个文件名(./..也是文件名)开始,表示一个文件对于当前工作路径的相对路径,例如在上图中,我们当前的工作路径为 /home/droh,那么文件 hello.c的相对路径就是./hello.c
Reference
Randal E. Bryant, David R. O’Hallaron - Computer Systems. A Programmer’s Perspective [3rd ed.] (2016, Pearson)