1、文件IO基础
通用的IO模型主要涉及4个函数:open(),read(),write(),close()。此外涉及文件内部指针的移动为lseek()。
文件描述符:一个int类型的数据,open()返回一个非负整数。
关于文件描述符: 标准输入:0,标准输出:1,标准错误:2。
2、文件IO深入了解:
1、文件描述符:文件描述符就是每个进程的文件描述符表中的index,每个文件描述符表中的每项都指向一个文件表,多项可以指向同一个文件表,文件表为文件描述信息的结构体。
2、open,write,read,close,lseek,每个文件表结构体都有一个指向文件写入文件位置的指针,使用lseek进行控制文件位置。
3、静态文件和inode,静态文件:没有打开的在磁盘中存放的文件。文件存取的最小单位是block(通常大小是4kb)。磁盘中有两个分区,inode分区和数据区。inode分区存放inode表,不同的inode表示不同的文件,每一个文件都必须对应与一个inode,inode实质上是一饿个结构体。
关于inode和文件的关系,硬链接:多个文件名(目录项)共享同一个 inode。
机制 | 是否多 inode 指向同一文件? | 备注 |
---|---|---|
硬链接 | ❌ 否(共享同一 inode) | 所有硬链接 inode 相同 |
符号链接 | ✔️ 是(独立 inode) | 存储目标路径,非实际数据 |
文件描述符 | ❌ 否(共享 inode) | 内核通过文件表间接管理 |
4、返回错误和errno。errno中存储错误值。
5、exit、_exit、_Exit。
6、空洞文件,例子:使用lseek(),从文件的起始位置的偏移处开始填写,前面不进行内容填写。这样就形成了空洞,但是实际的文件大小不会包含空洞的大小,但是ls -l显示的话,文件大小会包含空洞的大小。
7、O_APPEND 和 _OTRUNC 标志。一个进行原子操作,O_APPEND仅仅对写偏移固定到文件末尾,对读偏移无影响,lseek都无法对写偏移进行更改,一个对文件进行丢弃。
8、多次打开文件,多个文件表文件,导致文件覆盖,使用dup和dup2函数,进行文件描述符复制。对于文件描述符、文件表以及inode节点,都是多对一或者一对一的映射关系,但是不能是一对多的映射关系。
9、 原子操作和竞争冒险:O_APPEND实现原子操作,pread和pwrite系统调用是原子操作。
10、fcntl和ioctl系统调用,fcntl函数可以对一个已经打开文件描述进行管理,设置文件描述符的各种属性,ioctl操作特殊文件或者硬件外设。
11、截断文件,truncate()和fturncate,其中fturncate,必须先open,并且具有写权限
3、标准IO库
1、标准IO是标准c库中用于文件I/O操作的库。
2、FILE指针:标准I/O描述文件的结构体。指向标准I/O缓冲区。
3、标准输入,标准输出,标准错误。0,1,2。
4、打开文件fopen,写文件fwrite,读文件fread,定位fseek。
5、检查或复位状态,feof(FILE* stream):检测stream结构体是否设置了end-of-file标志。达文件结尾时,FILE 结构体会设置end-of-file标志。ferror()函数:检测stream是否设置了错误标志。clearerr():清除end-of-file标志和错误标志。
6、格式话IO,printf,fprintf,dprintf(文件描述符),sprintf(没有指向输出的buffer的size),snprintf。
7、标准I/O缓冲:c库的标准I/o也提供了c语言的标准缓冲区。减少进程对系统内核缓冲区的I/O次数。fflush:刷新到系统内核缓冲区。其他刷新方式按行(默认方式,检测到‘\n’)。缓冲区满则刷新。或者设置不缓存。
8、文件I/O缓冲:linux2.4有了直接I/O,直接写入磁盘,不写入文件IO缓存区,
9、文件描述符和FILE指针相互转化。int fileno(FILE*),FILE* fdopen(int fd,const *mode);