第九章学习笔记

第九章 IO库函数

I/O库函数

I/O库函数是一系列文件操作函数

I/O库函数与系统调用

系统调用函数:open()、read()、write()、lseek()、close()
I/O库函数:fopen()、fread()、ferite()、fseek()、fclose()
每个I/O库函数的根都在对应的系统调用函数中。

I/O库函数的算法

(1)fread算法

(1)在第一次调用fread(时,FILE结构体的缓冲区是空的,fread()使用保存的文件描述符fd发出一个
n=read(fd,fbuffer,BLKSIZE);
系统调用,用数据块填充内部的fbuf[]。然后,它会初始化fbuf[]的指针、计数器和状态变量以表明内部缓冲区中有一个数据块。接着,通过将数据复制到程序的缓冲区,尝试满足来自内部缓冲区的fread()调用。如果内部缓冲区没有足够的数据,则会再发出一个read()系统调用来填充内部缓冲区,将数据从内部缓冲区传输到程序缓冲区,直到满足所需的字节数(或者文件无更多数据)。将数据复制到程序的缓冲区之后,它会更新内部缓冲区的指针、计数器等,为下一个fread()请求做好准备。然后,它会返回实际读取的数据对象数量。
(2)在随后的每次fread()调用中,它都尝试满足来自FILE结构体内部缓冲区的调用。当缓冲区变为空时,它就会发出read()系统调用来重新填充内部缓冲区。因此,fread()一方面接受来自用户程序的调用,另一方面向操作系统内核发出read()系统调用。除了read()系统调用之外,所有fread()处理都在用户模式映像中执行。它只在需要时才会进入操作系统内核,并且以一种最高效匹配文件的方式进人。它会提供自动缓冲机制,因此用户程序不必担心这些具体操作。

(2)fwrite算法

与fread算法相似,只是数据传输方向不一样。

(3)fclose算法

若文件以写的方式被打开,fclose()会先关闭文件流的局部缓冲区。然后,它会发出一个close(fd)系统调用来关闭FILE结构体中的文件描述符。最后,它会释放FILE结构体并将FILE指针重置为NULL。

使用I/O库函数或系统调用

fread()依赖read()将数据从内核赋值到内部缓冲区,然后从内部缓冲区将数据复制到程序缓冲区,他传输了两次数据相反,read()将数据从内核直接复制到程序的缓冲区,只复制一次。

I/O库模式

fopen()中的模式参数可以指定为:"r"、" w"、"a”,分别代表读、写、追加。每个模式字符串可包含一个+号,表示同司时读写,或者在写入、追加情况下,如果文件不存在则创建文件。
"r+":表示读/写,不会截断文件。
"w+":表示读/写,但是会先截断文件; 如果文件不存在,会创建文件。
"a+":表示通过追加进行读/写;如果文件不存在,会创建文件。

字符模式I/O

fgetc()返回的是整数,而不是字符。这是因为他必须在文件结束时返回文件结束符,文件结束符通常是一个整数—1,将它与文件流中的任何字符区分开。
对于fp=stdin或stdout,可能会使用c=getchar();putchar(c);来代替。对于运行时效来说,getchar()和putchar()通常不是getc()和putc()的缩小版本。相反,可以将他们实现为宏,以避免额外的函数调用。

行模式I/O

char *fgets(char *buf,int size,FILE *fp):从fp中读取最多为一行(以\n结尾)的字符。
int fputs(char *buf,FILE *fp):将buf中的一行写入fp中。

格式化I/O

格式化输入:(FMT=格式字符串)
scanf(char *FMT,&items);
fscanf(fp,char *FMT,&items);
格式化输出:
printf(char *FMT,items);
fprintf(fp,char *FMT,items)

内存中的转换函数

sscanf(buf,FMT,&items);
sprintf(buf,FMT,items);
sscanf()和sprintf()并非I/0函数,而是内存中的数据转换函数。

其他I/O库函数

fseek()、ftell()、rewind():更改文件流中的读/写字节位置。
feof()、ferr()、fileno():测试文件流状态。
fdopen():用文件描述符打开文件流。
freopen():以新名称重新打开现有的流。
setbuf()、setvbuf():设置缓冲方案。
popen():创建管道,复刻子进程来调用sh

限制混合fread-fwrite

当某文件流同时用于读/写时,就会限制使用混合fread()和fweite()调用。规范要求每对fread()和fweite()之间至少有一个fsweek()或ftell()。

文件流缓冲

每个文件流都有一个FILE结构体,其中包含一个内部缓冲区。对文件流进行读写需要遍历FILE结构体的内部缓冲区。文件流可以使用三种缓冲方案中的一种。
无缓冲:从非缓冲流中写入或读取的字符将尽快单独传输到文件或从文件中传输。
行缓冲:遇到换行符时,写入行缓冲流的字符以块的形式传输。
全缓冲:写入全缓冲流或从中读取的字符以块大小传输到文件或从文件传输。这是文件流的正常缓冲方案。

变参函数

编程项目:类printf函数

项目规范

项目基本代码

myprintf()算法

假设格式字符串fmt=“char=%c string=%s integer=%d u32=%x\n”。这意味着分别有 char、char*、int、unsigned int和type的4个附加参数。myprint()的算法如下:
(1)扫描格式字符串fmt。打印任何不是%的字符。对于每个‘n’字符,打印一个额外的'\r字符。
(2)当遇到‘%’时,得到的下一个字符必须是‘c’、‘s’、‘u’、‘d’或‘x’中的一个。使用va_arg(ap,type)来提取相应的参数。然后后通过参数类型调用打印函数。
(3)当fmt字符串扫描结束时,算法结束。

项目改进

posted @ 2021-09-19 22:43  金嗷  阅读(36)  评论(0编辑  收藏  举报