第一章太简单,没东西可记。
2.3 IO基础
(1)基本函数原型
int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);当flags中带O_CREAT或者O_TMPFILE(创建的临时文件)时,才需要指定mode,mode指新建文件的访问权限。
ssize_t read(int fd, void *buf, size_t count);
ssize_t write(int fd, const void *buf, size_t count);
(2)lseek函数:修改文件读写指针的位置
off_t lseek(int fd, off_t offset, int whence);
whence:偏移量的参考值,取值SEEK_SET(文件头部) SEEK_END(文件尾部) SEEK_CUR(当前位置);off_t:指偏移后读写指针所在的位置
两个使用场景:
一是计算文件的大小:
int size = lseek(fd,0, SEEK_END);
二是计算当前读写指针的位置:
int off = lseek(fd, 0,SEEK_CUR);
3.1 文件管理
(1)block(块)包含多个sector(扇区)。磁盘分区以块为单位。
(2)磁盘分区或者格式化时,系统把磁盘空间分为管理表项区域和数据区。前者又称iNode。
(3)PCB全名process control block,即进程控制块,用来管理进程。内核为每个进程创建PCB数据块。
PCB数据块维护文件描述符表,该表管理当前进程所用的所有文件fd。文件描述符表中的每个节点又关联磁盘中具体的iNode。
3.2 errno和空洞文件
(1)errno是系统全局变量,表示系统调用某个函数(限指系统函数和库函数)失败后具体的错误编号,编号是大于0的int类型值。
注意:不是所有系统函数和库函数都使用errno的。是否支持可以看man手册。
(2)strerror()函数:打印错误编号errno对应的具体错误原因。
char *strerror(int errnum)
(3)perror()函数:不用传入错误编号,直接打印错误原因
void perror(const char *s) 入参可以为空字符串,也可以用户自定义。自定义时,打印内容是:”自定义” + ”: “ + ”系统错误”
(4)空洞文件的作用:
方便多线程写同一个文件。
两个应用场景:
一是迅雷下载文件
二是Vmware给虚拟机分配磁盘空间
(5)du命令(disk usage):用来显示文件的实际大小,如du -h test.txt:按K、M、G的单位方式显示文件test.txt的大小
ls命令:显示文件的逻辑大小。
3.3 open的O_TRUNC和O_APPEND标志
- O_TRUNC:把文件清空,大小置0
- O_APPEND:以追加的方式打开文件。
注意两点:
- O_APPEND和write操作是原子操作,即用了该标志打开了问题,代码后面一定要有write操作,在open和write之间如果调用了lseek去修改读写指针的位置,则对write的写位置不生效,write一定在文件尾部开始操作。
- O_APPEND标志对read操作的位置没有影响
3.4 O_APPEND在同一文件被多次打开中的使用。其作用是防止文件内容被覆盖,每个fd的write都发生在文件末尾。
同一个文件可以被多次打开!
3.5 文件描述符的复制
int dup(int oldfd) 返回值是自动生成的新的fd
int dup2(int oldfd, int newfd); newfd是用户指定的fd,如果这个已经存在了,则函数返回-1
3.6 文件共享
多个进程或者同一个进程内的多个线程同时对同一个文件做操作。
3.7
(1)竞争冒险:
多个进程(或者线程)对同一个文件做写操作时,可能文件内容被覆盖,结果可能和预期不一致。
(2)pread和pwrite函数:
ssize_t pread(int fd, void *buf, size_t count, off_t offset);
ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
和read、write函数相比,多了第三个入参-读写指针偏移量。即pread、pwrite在指定的偏移位置读写数据,读写之后,读写指针位置保持不变,不会向后偏移。
(3)O_EXCL标志
Open文件时,把判断文件是否存在和创建文件两个动作当做原子操作,即这两个动作不可被分割,无法拆开。
它类似于升级版的O_CREAT标志。用于文件共享的场景中。