之前读完了整本APUE,也是那种朦朦胧胧的读完的,好多知识点看一遍就过了,对着敲下例程,最近一直研究uboot、kernel底层。回过头发现好多都忘了,哎。好多函数原型都忘了,花时间重新再读一次,读的过程中发现经常会自己问自己些问题,不想上一次完全念书那样了。书读百遍其义自见。
APUE阅读——文件IO
- API,C库函数,系统调用三者的区别和联系
- 文件IO主要的函数:open,creat,close,write,read,lseek的使用,(从作用,参数,返回值三个方面说起)
- 文件描述符0、1、2分别是什么文件,定义的符号常量宏是什么(定义这些宏的头文件)。
- open函数详细写法。
- open函数的返回值文件描述符有什么特点。如何保证在一个给定的文件描述符打开一个文件。
- open函数第二个参数oflag的选择,每个宏的相应含义(定义这些宏的头文件)。
- 文件名(路径名)最大长度小于我们要创建的(路径)文件长度的处理方法。
- creat函数详细用法,等效于什么函数。creat函数的缺点
- close函数详细用法,进程终止时内核会自动关闭它打开的所有文件(所以可以不显式调用close,尽量还是调用)
- lseek函数详细用法,第三个参数whence的宏对应的含义。
- lseek参数中文件描述符关联的是管道、FIFO、网络套接字的情况,当查看当前偏移量时会返回-1.
- lseek的返回值一定是非负整数么,判断lseek函数是否调用失败的方法。
- 什么是空洞文件,如何创建空洞文件。(在命令行查看文件内容的方法)
- read函数详细用法,write函数详细用法,常见的出错原因
- 实际读到的字节少于要求读到字节长度的情况。
- 动态文件和静态文件分别是什么,存在于哪里
- 内核中是用什么来表示打开的文件(动态文件),简述里面的内容。
- 什么是原子操作,需要多个函数调用的情况会是原子操作么
- lseek到文件末尾和O_APPEND有什么不同(多进程下有区别)
- pread函数和pwrite函数详解用法。
- dup函数和dup2函数的用法,两者的区别,两者与fcntl函数的区别联系
- 什么是延迟写
- sync函数、fsync函数和fdatasync函数的详细用法和区别(数据库系统)
- fcntl函数的详细用法功能,简述它的各种功能用法
- fcntl有什么重要意义
- ioctl函数详细用法
- /dev/fd是一个目录,目录里面是0、1、2、、、n等文件。打开目录项下文件/dev/fd/n的作用是什么
- 为什么有/dev/fd这个目录
关于文件IO
这个应该是必须掌握的基础知识了,结果回头看也好多都忘了,上面的e题也是边看边想到的,合上书也只能答出80左右吧,都是基础的知识点了。
这个不能直接复制图片啊,之后再整理吧,多回头看看
-
API、C库函数、系统调用
API:操作系统提供的让应用程序与开发人员基于某软件或硬件得以访问一组例程的能力(不用读源码或者理解),不同操作系统不能通用
C库函数:编程语言(C语言)本身支持的一些基本函数(不是操作系统提供的),不同操作系统C库函数通用
系统调用:操作提供的可以进入内核态的接口,规定了用户进程进入内核的具体位置。系统调用是用户空间访问内核空间的唯一途径。(里面的核心是内核函数)
API和系统调用之间的区别:API是函数的定义,规定了这个函数的功能,跟内核无直接关系。而系统调用是通过中断向内核发请求,实现内核提供的某些服务。
调用的某些API函数(涉及到进入内核态),里面会封装到系统调用,例如read。某些则不会,例如abs()。系统调用是在内核态完成的,API是在库函数完成的 -
如下
-
linux中的标准输入,标准输出,标准错误
<unistd.h>中定义了幻数0、1、2来代替STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO -
open函数:
-
文件描述符是个非负整数,而且总是取当前未未打开的最小的文件描述符。
例如默认打开了012三个,新打开文件的文件描述符自动为4(未被占用的最小的),可以利用dup2函数来选择指定的。 -
在头文件<fcntl.h>中
下面这些是可以选择的,多个选项之间用|。
还有三个是可以选择的
-
可以选择截短或者出错,通过常量_POSIX_NO_TRUNC来决定
没有定义常量_POSIX_NO_TRUNC,则自动截短,程序不出错。
定义常量_POSIX_NO_TRUNC,整个路径名(某一文件名)超过PATH_MAX/NAME_MAX时,返回出错状态,errorno为ENAMETOOLONG. -
creat
创建的文件只能写不能读,所以需要creat创建的文件想读的话需要关闭重新打开。
-
close
-
lseek
-
当查看当前偏移量时会返回-1.(管道、FIFO、网络套接字)
-
对于普通文件肯定是非负整数,但某些设备允许负的偏移量,所以判断是不要<0,而是==-1
-
文件偏移量大于文件长度,下次写加长此文件,加长的部分就是空洞,被读为0.
有空洞的文件既是空洞文件(未写过的字节均为0),空洞文件利用lseek+write构建,在命令行用od –c 查看。 -
read、write
-
下面几种情况:(实际<max指定的)
读到普通文件末尾、从终端设备读(一次读一行)、从网络读(网络的缓冲机制),从管道或者FIFO读(里面内容有限,读完了),读到一半被信号量中断
write常见出错:磁盘写完了,超过给定进程给的文件长度。 -
静态文件磁盘、动态文件内存中(类似uboot环境变量那样操作)
-
三种数据结构:进程表项->文件表项->V节点表项
V节点和i节点相应内容:待补充 -
原子操作(atomic operation)多步组成的操作,要么不执行,要么执行就执行完。
原子操作不可能只执行其中某一步,执行也不会被打断。多个函数调用不会是原子操作,因为两个系统调用之间,内核会临时挂起该进程。 -
考虑多进程下,往一个文件下添加数据。
采用lseek+write写和O_APPEND open然后write这两种方法,前者不可以,SEEK_END会被别的进程改变。 -
pread/pwrite
-
dup、dup2
fcntl函数也可以复制文件描述符
-
延迟写:缓冲区——>输出队列——>磁盘(满足条件:缓冲区满了、到达队首)
内核中有高速缓冲区,磁盘I/O,往文件里写内容时,不会直接把数据放入磁盘,而是先存放在一个缓冲区,缓冲区满了或者需要用到该缓冲区存别的磁盘快数据。将该缓冲排入输出队列。到达队首后进行实际的I/O操作写入磁盘。 -
sync、fsync和fdatasync
sync:把所有修改过的块缓冲区排入写队列,然后返回。(注意还没有到磁盘呢)
fsync:对指定的fd单一文件起作用,并且等待到写入磁盘才返回。(数据+文件属性)
fdatasync:类似fsync,只影响数据部分,文件属性不关注 -
fcntl函数
-
只知道打开的文件描述符时,就可以更改文件性质!,不用知道文件名字。
例如O_SYNC同步写,要知道文件名字才能实现。利用fcntl也可以实现 -
1
-
复制文件描述符n。(假定n是打开的文件)
-
主要为shell使用,能够使用路径名作为调用参数的程序。