标准IO函数

标准IO

IO缓冲的必要性

所有磁盘都是以作为基本操作单元,因此IO要求最好数据大小与块对齐。对齐影响的为BIO部分,而不是写页缓存,即写页缓存时,系统不会管是否快对齐,只有pdflush时,数据块加入BIO队列,内核才会填补数据以块对齐。所以页缓存一定程度上缓解了块对齐的问题,导致write和fwrite的更大差异在于系统调用的消耗。因此,应用程序的IO操作数据大小若没有块对齐,则内核会进行冗余操作保证块对齐,导致IO性能严重下降。内核通过延迟写,合并同块IO请求,预读等操作 ,以提高性能。用户空间缓冲IO也是为了提高性能。

为了保证IO操作对齐块,IO操作的数据大小应为块的整数倍如4096。所以预先分配一个 块整数倍大小的 buffer,当写输入时,缓冲到buffer中,直到数据到达一定长度(可能没有满,但是将多次 IO修补 变成一次 IO修补),再调用系统调用,将数据交给内核。当读数据时,一次尽量读 buffer大小,再从buffer中读取数据。

应用程序可以自己实现缓冲机制,也可以使用标准IO

标准IO函数

#include <stdio.h>
FILE *fopen(const char *filename, const char *mode);
参数
		filename-- 这是 C 字符串,包含了要打开的文件名称。
		mode-- 这是 C 字符串,包含了文件访问模式。
		
功能
		使用给定的模式mode打开filename所指向的文件。
		
返回值
		文件顺利打开后,指向该流的文件指针就会被返回。如果文件打开失败则返回 NULL,并把错误代码存在error中。
一般而言,打开文件后会做一些文件读取或写入的动作,若打开文件失败,接下来的读写动作也无法顺利进行,所以一般在 fopen() 后作错误判断及处理。
Mode描述文件状态
“r”打开文件仅供读取必须存在
“r+”打开文件供读取并写入必须存在
“w”创建新文件仅供写入若存在,则清空后再写入
“w+”创建新文件供读取并写入若存在,则清空后再写入
“a”打开文件附加写入若不存在,则创建新文件写入
“a+”打开文件读取并附加写入若不存在,则创建新文件写入

mode虽然还有b,但是linux忽略此值,linux以相同方式处理文本文件和二进制文件。

int fgetc(FILE *stream)
参数
		stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要在上面执行操作的流。
		
功能
		从指定的流 stream 获取下一个字符(一个无符号字符),并把位置标识符往前移动。
		
返回值
		该函数以无符号 char 强制转换为 int 的形式返回读取的字符,如果到达文件末尾或发生读错误,则返回 EOF。		

fgetc返回值必须保存再int变量中,将他存放在char变量是常见但危险的错误。

int ungetc(int char, FILE *stream)
参数
		char -- 这是要被推入的字符。该字符以其对应的 int 值进行传递。
		stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了输入流。
		
功能
		把字符 char(一个无符号字符)推入到指定的流 stream 中,以便它是下一个被读取到的字符。
		
返回值
		如果成功,则返回被推入的字符,否则返回 EOF,且流 stream 保持不变。		
char *fgets(char *str, int n, FILE *stream)
参数
		str -- 这是指向一个字符数组的指针,该数组存储了要读取的字符串。
		n -- 这是要读取的最大字符数(包括最后的空字符)。通常是使用以 str 传递的数组长度。
		stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要从中读取字符的流。
		
功能
		从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。
		
返回值
		如果成功,该函数返回相同的 str 参数。如果到达文件末尾或者没有读取到任何字符,str 的内容保持不变,并返回一个空指针。如果发生错误,返回一个空指针。		

读取size-1个字节,并存储到str,最后加上\0,读到EOF或一个newline后,便会停止读取动作。如果读到newline字符,则\n被存入str。可以用 fgetc代替fgets,尽管重复调用 fgetc,会导致一定开销,但相对于IO对齐,所以这个开销并不大。

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
参数
		ptr -- 这是指向带有最小尺寸 size*nmemb 字节的内存块的指针。
		size -- 这是要读取的每个元素的大小,以字节为单位。
		nmemb -- 这是元素的个数,每个元素的大小为 size 字节。
		stream -- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输入流。

功能
		从给定流 stream 读取数据到 ptr 所指向的数组中。
		
返回值
		成功读取的元素总数会以 size_t 对象返回,size_t 对象是一个整型数据类型。如果总数与 nmemb 参数不同,则可能发生了一个错误或者到达了文件末尾。		

读取 size * nmenb 个字节,使用此函数,用于读取二进制数据。

int fputc(int char, FILE *stream)
参数
		char -- 这是要被写入的字符。该字符以其对应的 int 值进行传递。
		stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符的流。
		
功能
		把参数 char 指定的字符(一个无符号字符)写入到指定的流 stream 中,并把位置标识符往前移动。
		
返回值
		如果没有发生错误,则返回被写入的字符。如果发生错误,则返回 EOF,并设置错误标识符。		

将字符char转换成unsigned char ,写入stream。

int fputs(const char *str, FILE *stream)
参数
		str -- 这是一个数组,包含了要写入的以空字符终止的字符序列。
		stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符串的流。
		
功能
		把字符串写入到指定的流 stream 中,但不包括空字符。
		
返回值
		该函数返回一个非负值,如果发生错误则返回 EOF。		
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
参数
		ptr -- 这是指向要被写入的元素数组的指针。
		size -- 这是要被写入的每个元素的大小,以字节为单位。
		nmemb -- 这是元素的个数,每个元素的大小为 size 字节。
		stream -- 这是指向 FILE 对象的指针,该 FILE 对象指定了一个输出流。
		
功能
		将 ptr 所指向的数组中的数据写入到给定流 stream 中。
		
返回值
		如果成功,该函数返回一个 size_t 对象,表示元素的总数,该对象是一个整型数据类型。如果该数字与 nmemb 参数不同,则会显示一个错误。		
long int ftell(FILE *stream)
参数
		stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
		
功能
		返回给定流 stream 的当前文件位置。
		
返回值
		该函数返回位置标识符的当前值。如果发生错误,则返回 -1L,全局变量 errno 被设置为一个正值。		
int fseek(FILE *stream, long int offset, int whence)
参数
		stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
		offset -- 这是相对 whence 的偏移量,以字节为单位。
		whence -- 这是表示开始添加偏移 offset 的位置。它一般指定为下列常量之一:
    		SEEK_SET		文件的开头
    		SEEK_CUR		文件指针的当前位置
    		SEEK_END		文件的末尾
功能
		设置流 stream 的文件位置为给定的偏移 offset,参数 offset 意味着从给定的 whence 位置查找的字节数。
		
返回值
		如果成功,则该函数返回零,否则返回非零值。	
int fprintf(FILE *stream, const char *format, ...)
参数
		stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
		format -- 这是 C 字符串,包含了要被写入到流 stream 中的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是 %[flags][width][.precision]
		
功能
		发送格式化输出到流 stream 中。
		
返回值
如果成功,则返回写入的字符总数,否则返回一个负数。		
int sprintf(char *str, const char *format, ...)
参数
		str -- 这是指向一个字符数组的指针,该数组存储了 C 字符串。
		format -- 这是字符串,包含了要被写入到字符串 str 的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是 %[flags][width][.precision][length]specifier
		
功能
		发送格式化输出到 str 所指向的字符串。
		
返回值
		如果成功,则返回写入的字符总数,不包括字符串追加在字符串末尾的空字符。如果失败,则返回一个负数。		

int feof(FILE *stream)
参数
		stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了流。
		
功能
		测试给定流 stream 的文件结束标识符。
		
返回值
		当设置了与流关联的文件结束标识符时,该函数返回一个非零值,否则返回零。		
int fclose(FILE *stream)
参数
		stream -- 这是指向 FILE 对象的指针,该 FILE 对象指定了要被关闭的流。
		
功能
		关闭流 stream。刷新所有的缓冲区。
		
返回值
		如果流成功关闭,则该方法返回零。如果失败,则返回 EOF。		

缓存控制机制

void setbuf(FILE *stream, char *buffer)
参数
		stream -- 这是指向 FILE 对象的指针,该 FILE 对象标识了一个打开的流。
		buffer -- 这是分配给用户的缓冲,它的长度至少为 BUFSIZ 字节,BUFSIZ 是一个宏常量,表示数组的长度。
		
功能
		定义流 stream 应如何缓冲。该函数应在与流 stream 相关的文件被打开时,且还未发生任何输入或输出操作之前被调用一次。

线程安全

标准IO具备线程安全。在内部,它有一个锁(lock)和锁计数(lock count)。因此单个函数执行环境内,标准IO是原子的。

但是许多程序希望的原子性大于函数调用层次。如应用希望多个写操作都能原子。为此标准IO提供了一系列函数。

void flockfile(FILE *stream);
void funlockfile(FILE *stream);
int ftrylockfile(FILE *stream);

标准IO存在的问题

标准IO最大的问题: 性能受到两次复制的影响。即内核页缓存 到 标准IO缓冲,标准IO缓冲 到 用户提供buf。

改进方法:

读操作:读返回一个指向标准IO缓冲区的指针,用户可以直接操作缓冲区里的数据,用户自己决定是否复制这些数据

写操作:调用写操作时,不复制数据,只记录指针,当准备刷新数据到内核时,扫描存储的指针列表,以写出数据,使用 writev 实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值