标准I/O
标准I/O
C标准库中提供了标准I/O库(简称stdio),它实现了跨平台的用户缓冲解决方案。这个标准I/O库使用简单,功能强大
接下来主要讨论使用C标准库完成打开、关闭和读写操作。在应用中使用标准I/O还是直接使用系统调用,需要权衡应用的需求和行为
文件指针
标准I/O程序集并不是直接操作文件描述符。相反,他们通过唯一标识符,即文件指针来操作。在C标准库中,文件描述符和文件指针一一映射。文件指针是由指向类型定义FILE的指针表示
在标准I/O中,打开的文件成为“流”。流可以被打开用来读、写或者二者兼有
打开文件
文件通过fopen()打开以供读写操作:
1 |
|
该函数根据mode参数,按指定模式打开path所指向的文件,并给他关联上新的流
模式
参数mode描述如何打开指定文件,它可以是以下字串之一:
mode | description |
---|---|
r | 以只读模式打开文件。流指针指向文件开始 |
r+ | 以读写模式打开文件。流指针指向文件开始 |
w | 以只写模式打开文件。如果文件存在,文件会被清空,如不存在,就会被创建。流指针指向文件开始 |
w+ | 以读写模式打开文件。如果文件存在,文件会被清空,如不存在,就会被创建。流指针指向文件开始 |
a | 以追加写模式打开文件。如果文件不存在,就会被创建。流指针指向文件尾。所有的写入都是追加到文件的末尾 |
a+ | 以追加读写模式打开文件。如果文件不存在,就会被创建。流指针指向文件尾。所有的写入都是追加到文件的末尾 |
举个例子:
1 |
|
通过文件描述符打开流
fdopen()会把一个已经打开的文件描述符转换成流:
1 |
|
fdopen()的可能模式和fopen()相同,而且必须和初始打开文件描述符的模式匹配,可以指定模式w和w+,但是它们不会清空文件
文件描述符并没有被复制,而只是关联了一个新的流。关闭流也会关闭相应的文件描述符
关闭流
fclose()函数会关闭给定的流:
1 |
|
再关闭前,所有缓冲但还没有写出的数据都会被写出。成功返回0,失败返回EOF并设置相应的errno值
关闭所有流
fcloseall()函数会关闭和当前进程关联的所有流,包括标准输入、标准输出和标准错误:
1 |
|
在关闭前,所有的流都会被写出。这个函数始终返回0,它是Linux所特有的
从流中读数据
C标准库实现了多种从流中读数据的方法。本次主要记录最常用的三种:每次读取一个字节;每次读取一行以及读取二进制数据
每次读取一个字节
通常情况下,理想的I/O模式是每次读取一个字符。函数fgetc()可以用来从流中读取单个字符:
1 |
|
该函数从stream中读取一个字符,并把该字符强制类型转换成unsigned int返回。强制类型转换是为了能够表示文件结束或错误:在这两种情况下都会返回EOF。fgetc()的返回值必须确保存成int类型。
1 |
|
stream指向的流必须以可读模式打开
把字符放回到流中
标准输入输出提供了一个函数可以把字符放回到流中。当流读取的最后一个字符,如果不需要该字符的话,可以把它放回流中。
1 |
|
成功返回c,失败返回EOF
每次读取一行
函数fgets()会从指定流中读取一个字符串:
1 |
|
该函数从stream中读取size-1个字节的数据,并把结果保存到str中。读完最后一个字节后,缓冲区会写入空字符(\0)。当读到EOF或换行符时,会结束读。如果读到换行符,会把\n写入str中。
fgets()成功时,返回str,失败时,返回NULL
1 |
|
读取任意字符串
通常,基于行的读取fgets()函数是很有用的。但是很多时候,它又会带来很多麻烦。比如不想要分隔符,或者想要自己设置分隔符,这时就需要用fgetc()来实现fgets()的功能了:
1 |
|
可以优化代码支持在任意分隔符d处停止读数据:
1 |
|
读二进制文件
很多时候,读取一个字符或一行是不够的,为了解决这个问题,标准I/O库提供了fread()函数:
1 |
|
调用fread()会从stream中读取nr项数据,每项size个字节,并将数据保存到buf所指向的缓冲区中。文件指针向前移动读出数据的字节数
返回读到的数据项的个数(注意:不是读入字节数!!!)。如果读取失败或文件结束,返回一个比nr小的数,不幸的是必须使用ferror()或feof()函数,才能判断是失败还是文件结束
向流中写数据
和读相同,本次也介绍三个最常用的写数据的方法:每次写一个字节,每次写一个字符串,和写二进制数据
写入单个字符
和fgetc()函数对应的是fputc():
1 |
|
fputc()函数将参数c所表示的字节(强制类型转换成unsigned char)写到指针stream所指向的流。成功返回c,否则,返回EOF,并设置相应的errno值
1 |
|
写入字符串
函数fputs()用于向指定流写入整个字符串:
1 |
|
fputs()函数会把str所指向的所有字符串都写入stream指向的流中,不会写入结束标记符。成功时返回非负整数;失败时,返回EOF
写入二进制数据
和fread()函数对应,标准I/O提供了fwrite()函数:
1 |
|
调用fwrite()会把buff所指向的nr个数据写入stream中,每个数据长为size
成功时返回写入的数据项个数,出错时,返回值小于nr
标准I/O例程
1 |
|