第5章:
主要介绍了文件I/O更深入的一些内容。
原子操作,将一个系统调用所要完成的所有动作作为一个不可中断的操作,一次性执行;这样可以避免竞争状态(两个或多个共享资源的进程或线程的运行结果是一个无法预期的顺序)。
以独占方式创建一个文件:对文件是否存在的检查和创建文件属于同一个原子操作。防止新建文件的时候因为检查文件是否存在和新建文件之间发生中断(而其他进程也在新建相同文件名的文件),导致两个进程都认为自己是文件的创建者。
向文件尾部追加数据:将文件的偏移量的移动与数据的写操作属于同一个原子操作。防止多个进程同时往同一个文件尾部添加数据导致数据混乱。
fcntl(),对一个打开的文件描述符执行一系列的操作。
1 #include <fcntl.h> 2 3 int fcntl(int fd, int cmd, ...);
fd为文件描述符,cmd是决定具体操作,第三个参数(可选)用来设置为不同的类型。
cmd参数(部分),具体查看man手册:
| F_DUPFD | 复制文件描述符 |
| F_GETFD | 获取文件描述符 |
| F_SET_FD | 设置文件描述符 |
| F_GETFL | 获取文件访问模式和状态标志 |
| F_SETFL | 设置文件访问模式和状态标志 |
文件描述符与打开文件之间的关系:多个文件描述符可以指向同一个打开文件。他们的关系如下
文件描述符表、打开文件表和i-node表。打开文件表的条目成为打开文件句柄(open file handle)。
PS:如果两个不同的文件描述符指向同一个打开文件句柄,这两个文件描述符将共享相同的文件偏移量。(打开文件句柄里包含文件偏移量file offset)。
dup(),复制一个打开的文件描述符oldfd,并返回新的描述符。
dup2(),复制oldfd指定的文件描述符,返回newfd参数指定的描述符。
dup3(),参数与dup2()相同,添加了flags,用于修改系统调用行为。
1 #include <unistd.h> 2 3 int dup(int oldfd); 4 5 int dup2(int oldfd, int newfd); 6 7 int dup3(int oldfd, int newfd, int flags);
成功调用返回新的文件描述符,失败返回-1。
pread()和pwrite(),在指定参数所指定的位置进行文件I/O操作,但不改变文件的偏移量。
1 #include <unistd.h> 2 3 ssize_t pread(int fd, void *buf, size_t count, off_t offset); 4 5 ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
fd为文件描述符,buf为缓冲区, count为缓冲区字节数, offset为偏移量。
pread()成功调用返回读取的字节数,失败返回-1
pwrite()成功调用返回写入的字节数,失败返回-1
------------------------省略分散输入和集中输出,截断文件,非阻塞I/O和大文件I/O等一些知识点---------------
练习:
5-1,请使用标准文件I/O系统调用(open()和lseek())和off_t数据类型修改程序清单5-3中的程序。将宏_FILE_OFFSET_BITS的值设置为64进行编译,并测试该程序是否能够成功创建一个大文件。
1 /* 2 * ===================================================================================== 3 * 4 * Filename: large_file.c 5 * 6 * Description: 7 * 8 * Version: 1.0 9 * Created: 2014年03月17日 22时05分50秒 10 * Revision: none 11 * Compiler: gcc 12 * 13 * Author: alan (), alan19920626@gmail.com 14 * Organization: 15 * 16 * ===================================================================================== 17 */ 18 19 #define _FILE_OFFSET_BITS 64 20 #include <sys/stat.h> 21 #include <fcntl.h> 22 #include "tlpi_hdr.h" 23 24 int main(int argc, char *argv[]){ 25 int fd; 26 off_t off; 27 if(argc != 3 || strcmp(argv[1], "--help") == 0) 28 usageErr("%s pathname offset\n", argv[0]); 29 30 fd = open(argv[1], O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); 31 32 if(fd == -1) 33 errExit("open"); 34 35 off = atoll(argv[2]); 36 if(lseek(fd, off, SEEK_SET) == -1) 37 errExit("lseek"); 38 39 if(write(fd, "test", 4) == -1) 40 errExit("write"); 41 exit(EXIT_SUCCESS); 42 43 }