第九章学习笔记
第九章 I/O库函数
1.I/O库函数
- 系统调用是文件操作的基础,但它们只支持数据块的读/写。I/O库函数是一系列文件操作函数。
2.I/O库函数与系统调用
- 在Unix/Linux中,I/O库函数建立在系统调用的基础上
- 系统调用函数:open() read() write() lseek() close()
- I/O库函数:fopen() fread() fwrite() fseek() fclose()
- fopen()使用字符串表示模式,在失败时会返回一个NULL指针
3.I/O库函数的算法
- fread算法
在第一次调用fread()时,FILE结构体的缓冲区是是空的,fread()使用保存的文件描述符fg发出一个
n = read(fd,fbuffer,BLKSIZE);
在随后的每次调用中都尝试满足来自FILE结构体内部缓冲区的调用
2. fwrite算法
- fwrite算法与fread算法相似,数据传输方向不同,在每次调用fwrite()时,它将数据写入内部缓冲区,并调整缓冲区的指针、计数器和状态变量,以跟踪缓冲区中的字节数。如果缓冲区已满,则发出 write()系统调用,将整个缓冲区写入操作系统内核
- fclose算法
- 若文件以写的方式被打开,fcloseO会先关闭文件流的局部缓冲区。然后,它会发出一个close(fd)系统调用来关闭FILE结构体中的文件描述符。它会释放FILE结构体,并将 FILE 指针重置为 NULL。
4.使用I/O库函数或系统调用
- fread()依赖read将数据从内核复制到内部缓冲区,然后从内部缓冲区将数据复制到程序的缓冲区。所以,它传输了两次数据。相反,read()将数据从内核直接复制到程序的缓冲区,只复制了一次。因此,对于以BLKSIZE为单位的读/写数据来说,read()本来就比fread()更高效,因为它只需要一个而不是两个复制操作。类似表述也适用于write()和 fwrite()。
5.I/O库模式
- "r+":表示读/写,不会截断文件。
- "w+":表示读/写,但是会先截断文件;如果文件不存在,会创建文件。
- "a+":表示通过追加进行读/写;如果文件不存在,会创建文件。
- 字符模式I/O
- fgetc()返回的是整数,而不是字符。
- 对于fp=stdin或stdout,可能会使用c=getchar();putchar(c);来代替。
- 行模式I/O
char *fgets(char *buf, int size,FILE*fp)
从fp中读取最多为一行(以 结尾)的字符
int fputs(char *buf,FILE*fp)
将buf中的一行写人fp中
3. 格式化I/O
- 格式化输入:(FMT=格式字符串)
scanf(char*FMT, &items); // from stdin
fscanf(fp,char *FMT, &items); // from file stream
- 格式化输出:
printf(char *FMT, items); // to stdout
fprintf(fp,char *FMT, items); // to file stream
- 其他I/O库函数
- fseek()、ftell()、rewind():更改文件流中的读/写字节位置
- feof()、ferr()、fileno():测试文件流状态
- fdopen():用文件描述符打开文件流
- freopen():以新名称重新打开现有的流
- setbuf0、setvbuf():设置缓冲方案
- popen():创建管道,复刻子进程来调用sh
6.文件流缓冲
- _IONBUF:无缓冲
- _IOLBUF:行缓冲
- _IOFBUF:全缓冲
- 此外,还有其他的setbuf()函数,是setvbuf()的变体。对于行缓冲流或全缓冲流,可用fflush(stream)立即清除流的缓冲区。
7.变参函数
- 在I/O库函数中, printf()相当独特,因为多种不同类型的可变数量参数可以调用它。C语言和C++仍然允许参数数量可变的函数。这些函数必须至少使用一个参数进行声明,后跟3个点。
8.编程项目:类printf函数
- 在Linux中,putcher(char c)可打印一个字符