APUE学习日记(一)

实际开始时间是2019年11月25号,以此来记录我的APUE学习之路,可能中间会有许多错误。

文件I/O

文件I/O是指不带缓冲的I/O,它直接调用内核的系统调用,这是与第5章标准I/O作对比,标准I/O是带缓冲的I/O。我是这么理解这两者的区别:
(1)文件I/O:程序(数据)—>内存缓冲—>硬盘(文件系统)。
(2)标准I/O:程序(数据)—>数组缓冲(buffer)—>内存缓冲—>硬盘。
也就是标准I/O完成操作后,实际没有写进内存,而还是写进寄存器,或者比内存更高级的缓存中?不知道正确与否。

1 文件描述符

unix系统万物皆为文件,在程序中每打开一个文件,都会返回一个文件描述符(int fd,实际非负整数),供内核引用。而相对于标准I/O,就是打开文件指针(FILE* fp)。
unix系统shell把文件描述符0、1、2分配给标准输入、标准输出、标准错误,并用符号常量STDIN_FILINO、STDOUT_FILENO、STDERR_FILENO来表示。

2 基础函数

(1)open和openat函数打开或创建文件,返回最小的未使用的文件描述符,若错误则返回-1。
(2)creat函数以只写创建文件。
(3)close函数关闭文件,不过当一个进程终止,内核会自动关闭。
(4)lseek设置当前文件偏移量,可以理解打开文件后,你的光标在哪。测试lseek是否出错,不要检测其是否<0,而要检测其返回值是否等于-1。
(5)read从当前文件偏移量处开始读文件,并将读取的文件放在buf中。
(6)write和read类似,只不过是写进buf中。

3 文件共享、I/O数据结构

unix可以在不同进程间共享打开文件,也就是不同进程可以同时打开同一个文件。

3.1 一个进程打开不同文件

I/O数据机构:
文件内核结构
(1)每个进程都有一个进程表,其里面的记录项有一个一位fd标志(文件描述符标志)和一个指向文件表项的指针
(2)内核为所有打开文件维持一个文件表,其里面的文件项如图所示。
(3)每个打开的文件都有都有一个v节点结构,包括v节点信息,也有指向i节点的指针。

3.2 两个进程打开同一个文件

在这里插入图片描述
注意点:
(1)多个进程打开同一个文件,每个进程都会获得各自的文件表,使每个进程都有自己的当前文件偏移量。
(2)但是对于打开的文件永远只有一个v节点表项。

4 原子操作

我们先看一个例子,当还没有O_APPEND追加写选项时,要想在文件尾部进行写,必须分成两部来进行。
(1)lseek定位到文件尾部;(2)进行write写。

if (lseek(fd, OL, 2) < 0)
	perror("lseek error");
if (write(fd, buf, 100) != 100)
	perror("write error");

这个对于只有一个进程时,是完全正确且没有错误的。可是一旦有多进程,就会出现问题。

让我们来假设有两个进程A和B,分别对同一个文件进行追加写。其可能的时间线是这样的:

在这里插入图片描述
(1)在进程A,lseek定位到文件尾(假设为1500)。
(2)此时内核进行进程切换,切换到B进程。进程B执行完全部过程,为文件写入了100字节,此时文件尾为1600。
(3)内核进行进程切换,进程A继续执行,因为不同进程打开同一文件都有各自的文件表,而之前A进程lseek将当前文件偏移量设置为1500,write函数理应也是从1500处写起,导致进程B写进的数据被覆盖。

所以这里提出原子操作的定义:原子操作指的是多步组成的一个操作
lseek和write可以合成一个原子操作pwrite,先执行lseek,再执行write。要么执行完所有步骤,要么不执行。

5 进阶函数

(1)pread和pwrite,原子操作。
(2)dup和dup2复制现有的文件描述符到一个新的文件描述符。
在这里插入图片描述
注意:每个文件描述符都有它自己一套的文件描述符标志
(3)fsync、fdatasync、sync函数,将内核的缓冲区文件写进磁盘,保证磁盘上的文件系统和缓冲区中的内容一致
(4)fcntl函数可以改变已经打开文件的属性

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值