目录
前言
神兽中的怪兽读写专用函数:fread()和fwrite()
阅读此篇需要有上一篇的基础:一起笨笨的学C——011文件基操-CSDN博客
正文
fread与fwrite简介:
fgetc、fputc,一口一个字符;
fgets、fputs,一口一行字符;
fread、fwrite,一口一块字符。
哪种数据有块的概念?没错,结构体!只要建立,就在内存中暴力的占领一块区域(好像被我描述的很残暴)。fread、fwrite因为它们应运而生。
原型及使用:
fread()原型:
#include <stdio.h>
size_t fread(const coid *ptr, //size_t即unsigned long
size_t size, size_t count, FILE *stream);
应用举例: fread(&stud, sizeof(struct STUDENT), count, fp);
fwrite()原型:
#include <stdio.h>
size_t fwrite(const coid *ptr, //size_t=unsigned long
size_t size, size_t count, FILE *stream);
使用举例:fwrite(&stud, sizeof(struct STUDENT), count, fp);
两个函数的特点:
- 在文件与结构体变量之间读写数据时,通常count都取1,即一块一块的读取。
- fread与fwrite只能以二进制的形式打开文件,所以打开i方式中要有b。
- 文件不加后缀就是二进制文件。
- fread与fwrite一起使用时,最好单独用完其中一个就关闭,再用另一个。即fopen、freadfclose或者fopenfwritefclose这样。
- fread的返回值是实际读取的“块数”count。如果读到文件末尾或发生错误则返回比count小的数或返回0,总之不等于count。所以与fgetc、fgets一样,要用fread的返回值和feof的返回值配合判断是否读到文件末尾。
fread代码:
#include <stdio.h>
#include "dbg.h"
struct Student{
char name[20];
int age;
char sex;
char num[20];
};
//void Read(FILE *,struct Student *);
int main(int argc, char *argv[])
{
int i ;
int count;
FILE *fp= fopen("stu_list", "rb");
struct Student buf[100];
// check((fp = fopen("stu_list", "rb")) != NULL, "Can't open the fail!");
fseek(fp, 0, 2);
count = ftell(fp);
count = ftell(fp)/sizeof(struct Student);//用了ftell加fseek组合就不用判断是否读到文件末尾了,因为已经知道有多少数据,可以精确读取了。
fseek(fp, 0, 0);
for (i=0; i<count; ++i){
fread(&buf[i], sizeof(struct Student), 1, fp);//此处&buf[i]也可以写作buf+i,把数组首地址当做指针用
}
for (i=0; i<count; ++i){
printf("姓名: %s, 年龄: %d, 性别: %c, 学号:%s\n", buf[i].name, buf[i].age, buf[i].sex, buf[i].num);
}
fclose(fp);
return 0;
}
/*
error:
return -1;
}
xxvoid Read(FILE *fp, struct Student *p)
{
}
*/
fwrite代码:
#include <stdio.h>
#include "dbg.h"
struct Student
{
char name[20];
int age;
char sex;
char num[20];
}
;
int main(int argc, char *argv[])
{
int i;
int cnt;//xuesheng de number
FILE *fp;
struct Student stud[10];
printf("How many students do you want to input?");
scanf("%d", &cnt);
check((fp = fopen("stu_list", "wb")) != NULL,"Can't open the file");
printf("Please input the name, age, sex, number:\n");
for (i=0; i<cnt; ++i)
{
scanf("%s%d %c%s", stud[i].name, &stud[i].age, &stud[i].sex, stud[i].num);
check(fwrite(&stud[i], sizeof(struct Student), 1, fp) ==1, "FIle write erro");
}
fclose(fp);
return 0;
error:
return -1;
}
后语
- 本章中还讲了用fread与fwrite删除文件中的数据块。它们主要针对链表,而链表还在好几个习题之后,虽然我也能弄懂,但是还是按照”笨办法“这本书架构来吧。
- 程序设计经验摘抄:“除非迫不得已,不要使用全局变量”。在程序设计中划分模块时要求模块的“内聚性“强,与其它函数关联性弱。函数之间通过实参与形参进行联系,这样函数间的关系就会很单一,更清晰。如果用全局变量,任何一个函数都可以改变全局变量的值,这样就很难跟踪该值的变化。
- scanf容错处理小妙招:,scanf后面加上的那一句清空输入缓冲区,以防用户乱输入。(如果用的多,可以考虑宏缩短语句的吧!)
printf(”a= “); scanf("%f", &a); while(getchar()! = '\n'); printf("b= "): scanf("%f", &b); while(getchar() != '\n');