系统相关
首页 > 系统相关> > 《Unix/Linux系统编程》第九章学习笔记

《Unix/Linux系统编程》第九章学习笔记

作者:互联网

第9章 I/O库函数

9.1 I/O库函数

系统调用是文件操作的基础,但它们只支持数据块的读/写。
实际上,用户程序可能希望以最适合应用程序的逻辑单元读/写文件,如行、字符、结构化记录等,而系统调用不支持这些逻辑单元。I/O库函数实现了这一目的。


9.2 I/O库函数与系统调用


9.3 I/O库函数的算法

9.3.1 fread算法

1.在第一次调用fread()时,FILE结构体的缓冲区是空的,fread()使用保存的文件描述符fd发出一个

n = read(fd, fbuffer, BLKSIZE);

系统调用,用数据块填充内部的fbuf[]。然后,它会初始化fbu[]的指针、计数器和状态变量,以表明内部缓冲区中有一个数据块。接着,通过将数据复制到程序的缓冲区,尝试满足来自内部缓冲区的fread()调用。如果内部缓冲区没有足够的数据,则会再发出一个read()系统调用来填充内部缓冲区,将数据从内部缓冲区传输到程序缓冲区,直到满足所需的字节数(或者文件无更多数据)。将数据复制到程序的缓冲区之后,它会更新内部缓冲区的指针、计数器等,为下一个 fread()请求做好准备。然后,它会返回实际读取的数据对象数量。

2.在随后的每次fread()调用中,它都尝试满足来自FILE结构体内部缓冲区的调用。当缓冲区变为空时,它就会发出read()系统调用来重新填充内部缓冲区。因此,fread()一方面接受来自用户程序的调用,另一方面向操作系统内核发出 read()系统调用。除了read()系统调用之外,所有fread()处理都在用户模式映像中执行。它只在需要时才会进入操作系统内核,并且以一种最高效匹配文件的方式进入。它会提供自动缓冲机制。

9.3.2 fwrite算法

fwrite()算法与fread()算法相似,只是数据传输方向不同。最开始,FILE结构体的内部缓冲区是空的。在每次调用fwrite()时,它将数据写入内部缓冲区,并调整缓冲区的指针、计数器和状态变量,以跟踪缓冲区中的字节数。如果缓冲区已满,则发出 write()系统调用,将整个缓冲区写入操作系统内核。

9.3.3 fclose算法

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


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

对于以BLKSIZE为单位的读/写数据,使用系统调用比I/O库函数更高效。


9.5 I/O库模式

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

9.5.1 字符模式I/O
int fgetc(FILE *fp);            //get a char from fp, cast to int
int ungetc(int c, FILE *fp);    //push a previously char got by fgetc() back to stream
int fput(int c, FILE *fp);      //put a char to fp

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

9.5.5 其他I/O库函数
9.5.6 限制混合fread-fwrite

规范要求每对fread()和fwrite()之间至少有一个fseek()或ftell()。


9.6 文件流缓冲

每个文件流都有一个FILE结构体,其中包含一个内部缓冲区。对文件流进行读写需要遍历FILE结构体的内部缓冲区。文件流可以使用三种缓冲方案中的一种。

通过fopen()创建文件流之后,在对其执行任何操作之前,用户均可发出一个

setvbuf(FTLE *stream,char *buf, int node, int size)

调用来设置缓冲区(buf)、缓冲区大小(size)和缓冲方案(mode),它们必须是以下一个宏:

对于行缓冲流或全缓冲流,可用fflush(stream)立即清除流的缓冲区。


9.7 变参函数

目前,C语言和C++会强制执行类型检查,但这两种语言仍然允许参数数量可变的函数。这些函数必须至少使用一个参数进行声明,后跟3个点,如

int func(int m, int n ...)  //n = last specified parameter

在函数内部,可以通过C语言库宏访问参数:

void va_start(va_list ap,last); // start param list from last parameter
type va_arg(va_list ap, type);  // type = next parameter type
va_end(va_list ap);             // clear parameter list

标签:文件,调用,缓冲,编程,fread,Unix,FILE,Linux,缓冲区
来源: https://www.cnblogs.com/qwer6653/p/16684573.html