一、打开流
1、概念:
fopen函数打开一个特定的文件,并把一个流和这个文件相关联。
2、函数原型:
FILE *fopen(char const *name, char const *mode);
释:
1)name表要打开的文件或设备的名称。
2)mode表流是用于只读、只写还是既读又写,以及它是文本流还是二进制流。常用模式如下表所示:
| 读取 | 写入 | 添加 |
文本 | “r” | “w” | “a” |
二进制 | “rb” | “wb” | “ab” |
注:在mode中添加“a+”表示该文件打开用于更新,并且流允许写也允许读。
3) 函数返回FILE* 。
注意:
如果fopen函数执行成功,它返回一个指向FILE结构的指针,该结构代表这个新创建的流;如果函数执行失败,它就返回一个NULL指针,errno会提示问题的性质。如果程序不检查错误,这个NULL指针就会传给后续的I/O函数。
【例】
FILE *input;
input = fopen("data6", "r");
if(input == NULL){
perror("data6");
exit(EXIT_FAILURE);
}
二、关闭流
1、概念:
流是用函数fclose关闭的。
2、函数原型
int fclose(FILE *f);
对于输出流,fclose函数在文件关闭之前刷新缓冲区。如果它执行成功,fclose返回零值,否则返回EOF。
【例】
#include<stdio.h>
#include<stdlib.h>
int main(int ac, char **av)
{
int exit_status = EXIT_SUCCESS;
FILE *input;
while(*++av != NULL){
input = fopen(*av, "r");
if(input == NULL){
perror(*av);
exit_status = EXIT_FAIFURE;
}
if(fclose(input) != 0){
perror("fclose");
exit(EXIT_FAILURE);
}
}
return exit_status;
}
释:
该程序把它的命令行参数解释为一列文件名。它打开每个文件并逐个对它们进行处理。如果有任何一个文件无法打开,它就打印一条包含该文件名的错误信息,然后,程序继续处理列表中的下一个文件名。
注意:
任何有可能失败的操作都应该进行检查。
三、二进制I/O
1、作用:
把数据写到文件效率最高的方法是用二进制形式写入。因为,二进制输出避免了数值转换为字符串过程中所涉及的开销和精度损失。
2、函数:
fread函数用于读取二进制数据,fwrite函数用于写入二进制数据。
(1)原型:
size_t fread(void *buffer, size_t size, size_t count, FILE *stream);
size_t fwrite(void *buffer, size_t size, size_t count, FILE *stream);
释:
1)buffer是一个指向用于保存数据的内存位置的指针;
2)size是缓冲区中每个元素的字节数;
3)count是读取或写入的元数个数;
4)stream是数据读取或写入的流;
5)函数的返回值是实际读取或写入的流的数目,并非字节。
如果输入过程中出现错误,返回值可能比实际请求的元素数目要小。
【例】
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
FILE *fp = fopen("myfile", "w");
if(!fp){
printf("fopen error!");
}
const char *msg = "hello bit!\n";
int count = 5;
while(count--){
fwrite(msg, strlen(msg), 1, fp);
}
fclose(fp);
return 0;
}
四、流错误函数
1、feof函数
原型:int feof(FILE *stream);
释:如果流当前处于文件尾,feof函数返回真。
2、ferror函数
原型:int ferror(FILE *stream);
释:ferror函数报告流的错误状态,如果出现任何读/写错误函数就返回真。
3、clearerr函数
原型:void clearerr(FILE *stream);
释:clearerr函数对指定流的错误标志进行重置。
【例】
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
FILE *fp = fopen("myfile", "r");
if(!fp){
printf("fopen error!\n");
}
char buf[1024];
const char *msg = "hello world!\n";
while(1){
ssize_t s = fread(buf, 1, strlen(msg), fp);
if(s > 0){
buf[s] = 0;
printf("%s", buf);
}
if(feof(fp)){
break;
}
}
fclose(fp);
return 0;
}
五、标准情况
对一个进程预定义了3个流可以自动被进程使用,它们是标准输入、标准输出、标准错误。
这3个标准I/O流通预定义文件指针stdin、stdout和stderr加以引用。这3个文件指针定义在头文件<stdio.h>中,都是FILE*类型,即fopen的返回类型(文件类型)。
六、定位流
1、ftell函数
函数原型:
long ftell(FILE *fp);
返回值:
若成功,返回当前文件位置指示;若失败,返回-1L。
2、fseek函数
函数原型:
Int fseek(FILE *fp, long offset, int whence);
返回值:
若成功 返回0;若出错 返回-1。
3、rewind函数
函数原型:
void rewind(FILE *fp);
4、3个函数的使用
(1)二进制文件
对于一个二进制文件,其文件位置指示器是从文件起始位置开始度量,并以字节位度量单位的。
ftell用于二进制文件时,其文件就是字节的位置。要想使用fseek函数定位一个二进制文件,必须指定一个字节offset,以及解释这种偏移量的方式;whence的值有:SEEK_SET表示从文件的起始位置开始,SEEK_CUR表示从当前文件位置开始,SEEK_END表示从文件的末端开始。
(2)文本文件
对于文本文件,它们文件的当前位置不能以简单的字节偏移量来度量。
为了定位一个文本文件,whence一定要是SEEK_SET,而且offset只能有两种值:0(后退到文件的起始位置),或是对该文件的ftell所返回的值。使用rewind函数也可将一个流设置到文件的起始位置。