文件的顺序读写
fgetc和fputc的介绍
fgetc
为字符输入函数,fputc
为字符输出函数,适用所以输入流和输出流
函数原型:
int fgetc ( FILE* stream );
该函数从stream
指向的输入流中读取unsigned char
型的下一个字符的值,并将其转换为int
型,并返回。若在流中检查到文件末尾,则设置该流的文件结束指示符并返回EOF
;如果发生读取错误,就设置该流的错误指示符并返回EOF
。
int fputc ( int character, FILE * stream );
此函数运行时会先将character指定的字符转换为unsigned char型写入stream指向的输入流。此时如果定义了流的文件位置指示符(fseek,rewind等函数),就会向指示符指向的位置写入字符,并将流的文件位置指向下一个。在不支持文件定位或者以追加模式打开流的情况下,总是在文件的末尾追加字符。
知道上面这些,我们便可写这样一段代码实现文件的拷贝:
//将文件data2.txt的内容拷贝到文件data1.txt int main() { FILE* pfread = fopen("data1.txt", "r"); if (pfread == NULL) { perror("fopen-1"); return 1; } FILE* pfwrite = fopen("data2.txt", "w"); if (pfwrite == NULL) { perror("fopen-2"); //如果上面文件能打开,此文件打开错误情况 //此时需关闭上一个文件 fclose(pfread); pfread = NULL; return 1; } char ch = 0; //拷贝内容 while ((ch = fgetc(pfread)) != EOF) { fputc(ch, pfwrite); } //关闭文件 fclose(pfwrite); pfwrite = NULL; return 0; }
fgets和fputs的介绍
fgets
为文本行输入函数,fputs
为文本行输出函数,适用所以输入流和输出流
函数原型:
char * fgets ( char * str, int num, FILE * stream );
此处的str
指向便是一个字符数组,此方法读取时,指定读num个后,若一行未读完,下次读取时以此向后读;若num大于一行字符串个数时,读到'\n'
停止(即读完)。
对于此函数的返回值: 如果读取成功且未读到文件的末尾,那么便会返回str
(即指向读到字符串的指针);若在流中检查到文件末尾,则设置该流的文件结束指示符并返回NULL
;如果发生读取错误,就设置该流的错误指示符同样返回NULL
。
int fputs ( const char * str, FILE * stream );
这两个函数与fgetc
和fputc
用法相似,就不举例了。判断这两个函数读取结束的原因,同样也可以使用ferror
和feof
。
fscanf和fprintf的介绍
fscanf
为格式化输入函数,fprintf
为格式化输出函数,同样适用所以输入流和输出流,
函数原型:
int fscanf ( FILE * stream, const char * format, ... );
我们可以看出fscanf
函数是从stream
指向的流中读取数据。除此之外与scanf
别无二样。对于此函数的返回值:若没有发生任何转化就发生了输入错误,则返回EOF
,并设置该流的错误指示符;否则,返回成功赋值的输入项数;若在输入过程中发生匹配错误,则返回的输入项数会少于转换说明符对应的参数个数,甚至为0;
既然fscanf
函数会返回读取到的项数,那么判读此函数读取结束,便可如下设置:
while((fscanf(pf, "%d %s %lf\n",&a, arr, %f) == 3) { ; }
此循环的含义便是,每次从pf指向的文件中读取三个类型变量到a, arr, f中,每成功读取一次时fscanf便会返回3,此循环便会继续,直至读取结束返回值不再为3,以此达到遍历文件中的数据。
int fprintf ( FILE * stream, const char * format, ... );
此函数会向stream
指向的流中输出数据,其他取printf
相同。对于返回值,成功时会返回写入的数据个数;若发生错误是设置流的错误指示符并返回负值。
用法也很简单,如果我们想向流pf
中写入十进制数,便可这样写:
int a = 10; fprintf(pf, "%d", a);
我们之前就了解过了标准输入流stdin
和标准输出流stdout
都是FILE
型的指针型,因此这些变量会直接传递给fscanf
和fprintf
的第一个参数。
讲到这,便可理解下面两条语句的功能是相同的:
scanf("%d", &a); fscanf(stdin, "%d", &s);
printf("%d", a); fprintf(stdout, "%d", a);
这样看,scanf
函数可以说是输入源被限制为标准输入流的fscanf
函数,printf
函数则是输出目标被限定为标准输出流的fprintf
函数。
fread和fwrite的介绍
fread
为二进制输入函数,fwrite
为二进制输出函数,这两个函数只适用于文件
函数原型:
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
fread
函数从stream
指向的流中读取个数为count
大小为size
的元素到ptr
中。若读取成功流已读到的字符数为单位向后移动。若发生错误则stream
的指向不可预测。此函数返回读取到大小为size
的元素个数,若提前读到文件末尾,返回值小于count
。
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
fwrite
函数从ptr
指向的字符串中写入count
个大小为size
的元素到stream
指向的流中。同样,若读取成功流已读到的字符数为单位向后移动。若发生错误则stream
的指向不可预测。此函数返回读取到大小为size
的元素个数,若提前读到文件末尾,返回值小于count
。
举个这两个函数实用的例子,当我们写通讯录时,存储联系人信息到文件,从文件中读取上次存储的联系人信息便可使用此函数,如下:
//导出之前存储的数据 void ContactLocate(Contact* con) { assert(con); PeoInfo info; FILE* pf; if ((pf = fopen("contact.txt", "rb")) == NULL) { printf("open fail\n"); return; } while(fread(&info, sizeof(PeoInfo), 1, pf))//信息读入info { ContactPushBack(con, info);//未插 } printf("\a历史数据读入成功\n"); }
//保存之前的数据 void ContactSave(Contact* con) { assert(con); FILE* pf; if ((pf = fopen("contact.txt", "wb")) == NULL) { printf("open fail\n"); return; } //向文件添加信息 for (int i = 0; i < con->size; i++) { fwrite(&con->ps[i], sizeof(PeoInfo), 1, pf); } fclose(pf); }
文件的随机读写
fseek的介绍
fseek
函数主要作用:根据文件指针当前的位置和偏移量来指定文件指针指向。
函数原型如下:
int fseek(FILE* stream, long int offset, int origin);
函数中的参数origin
有三种状态,分别为:
SEEK_SET
表示文件的开始位置;SEEK_CUR
表示文件指针当前指向的位置;SEEK_END
表示文件的末尾位置。
另一个参数offset
表示文件指针的偏移量,正为向前偏移,负为向后偏移。举个例子如果我们想把文件指针从开头向后偏移6个字符位置,便可这样写:
fseek(pf, 6, SEEK_SET);
ftell的介绍
ftell
函数作用是告诉我们当前文件指针所在的位置的偏移量,函数原型如下:
long int ftell ( FILE * stream );
如果成功使用便会返回文件指针相当于文件起始位置(即SEEK_SET
)的偏移量,如果函数使用失败便会返回-1
。
ftell
函数常常和fseek
函数联用,先使用fseek
根据当前文件指针位置设置偏移量,然后使用ftell
函数确定fseek
后的文件指针位置,具体使用如下:
fseek(pf, -3, SEEK_END); int pos = ftell(pf);
rewind的介绍
rewind
函数用法很简单,就是将文件指针重新指到文件的开始位置,原型如下:
void rewind ( FILE * stream );
feof和ferror的介绍
feof
函数的主要作用是在文件读取结束的时候,检测是否是因为遇到了文件结束标志EOF
,而读取结束,函数原型如下:
int feof ( FILE * stream );
而ferror
函数主要是在文件读取结束的时候,检测是否因为读取错误而结束,函数原型如下:
int ferror ( FILE * stream );
这两个函数用法极其相似又在一定程度上互补,所以通常将两函数一起使用来给出文件读取结束的原因。同时我们还要知道:读取文本判断是否结束时,fgetc
看返回值是否为EOF
, fgets
看返回值是否为NULL
。二进制文件判断读取结束,看实际读取个数是否小于要求读取个数。
不论是读取结束还是读取错误,此时的状态都会被记录在文件指针中,所以我们可以看到这两个函数参数都是文件指针类型。
使用这两个函数检测,代码通常如下:
//判断是什么原因结束的 if (ferror(fp)) puts("I/O error when reading");//读取错误 else if (feof(fp)) puts("End of file reached successfully");//读取结束