一:系统编程细节
1. 一切皆文件
1. VFS不仅包括file结构体,还有inode结构体和super block结构体
2. 在linux文件总共分成7种:
(1) 普通文件 :存储普通数据
(2) 目录文件 : 文件系统管理的重要文件类型
(3) 管道文件 :用于进程间通信的特殊文件,也称为命名管道FIFO
(4) 套接字文件 : 网络通信的特殊文件
(5) 链接文件 :间接访问另外一个目标文件
(6) 字符块设备文件 :字符设备在应用层的访问接口
(7) 块设备文件 : 块设备应用层的访问接口
2. 文件操作
1. 应用程序的一切行为都依赖于这个操作系统,但是这个操作系统的内部函数应用层的程序是不能直接被访问的
因此操作系统提供了系统调用接口。
3. 系统I/O
1. open()函数需要注意点:
(1) mode是八进制权限,比如0644或者0755等
(2) 它可以用来打开普通文件,块设备文件,字符设备文件,链接文件和管道文件
(3) open只能用来创建普通文件!每一种特殊文件的创建都有其特定的其他函数
(4) 其返回值就是一个代表这个文件的描述符,是一个非负整数
2. 文件描述符:0,1,2 分别代表: 标准输入,标准输出,标准出错
3. 在内核中打开的文件是用file结构体来表示的,每一个结构体都会有一个指针来指向它。
4. 一个进程与文件的关系:文件描述符的本质
进程控制块结构体
struct task_struct
{
*files--> struct files_struct
{
fd_array[*file]--> struct file
{
a.txt相关属性
};
};
};
5. 文件描述符:用户空间每一次调用open()函数都会使得内核实例化一个file{
}结构体
并将一个指向该结构体的指针一次存放在fd_array[]中,该指针所占据的数组下标就是其文件描述符。
6. read()和write()的注意点:
(1) 实际的读/写字节数要通过返回值来判断,参数count只是一个"愿望值"
(2) 当实际的读/写字节数小于count时,有以下两种情况:
<1> 读操作时,文件剩余可读字节数不足count.
<2> 读/写操作期间,进程收到异步信号
(3) 不管是读还是写,文件的位置偏移量(即内核中的f_pos)都会加上实际读/写的字节数,不断地往后偏移
7. lseek()只对普通文件有效,特殊文件无法调整偏移量的。
8. dup2()可以通过第2个参数newfd来指定一个文件描述符,如果这个指定的描述符已经存在,将会被覆盖
9. fcntl()函数里面的 struct flock结构体注意点:
(1) 对一个文件必须有可读可写的权限,才能分别对该文件加读记录锁和写记录锁
(2) 由于缓冲区的原因,应避免在涉及记录锁的场合使用标准I/O ,改用系统I/O函数调用
(3) 记录锁不会被通过fork()系统调用创建出来的子进程继承,但可以在进程执行execve()加载新代码之后继续保持
(4) 记录锁可以是协商性的,也可以是强制性的,默认是协商性的。
(5) 协商性的记录锁不对文件本身做任何处理,因此只能用于相互协作的进程之间。
(6) 强制性的记录锁将会作用于文件本身使得任何进程在读/写已经加了所的文件的相关区域时阻塞或发生错误。
10. 系统I/O 特点:
(1) 更具有通用性,不管是普通文件,管道文件,设备节点文件,套接字文件等都可以使用
(2) 简约性 ,对文件内数据的读写在任何情况下都是不带任何格式的,而且数据的读写也都没有经过任何缓冲处理
4. 标准I/O
1. 标准I/O特点:
(1) 标准I/O提供缓存区,增加数据的吞吐量
(2) 数据将会先存储在一个标准I/O缓冲区中,而后在一定条件下才能被一并flush(冲洗,或称刷新)至内核
而不是像系统I/O那样,数据直接被flush至内核。
2. getchar() 默认从标准输入设备读取一个字符
putchar()默认从标准输出设备输出一个字符
3. fgetc()和fputc()是函数,getc()和putc()是宏定义
4. 两组输入\输出函数一般成对使用,fgetc()和fputc(),getc()和putc(),getchar()和putchar()
5. fgets()与 fgetc()一样,当其返回NULL 时,不能确定究竟是达到文件末尾还是碰到错误,需要用到feof()/ferror()
进一步判断。
6. fgets()每次读取之多不超过size个字节的一行,所谓的一行,即数据之多包含一个换行符'\n'
5. 文件属性
1. 文件属性