二进制写文件
函数fwrite
函数返回类型为读取到的完整的元素的个数,参数为所写的元素的地址,一个元素的大小,写的元素的个数,文件指针。
这里需要注意的是,为了输入数据,打开的是一个二进制文件,这里fopen打开方式为rb(只读)或这rw(只写)。
例如
函数fread
二进制读文件
函数整体结构与fwrite相似,函数返回类型为读取到的完整的元素的个数,参数为所写的元素的地址,一个元素的大小,写的元素的个数,文件指针。
运行结果,打开文件,我们会发现里面是看不懂的符号,即里面存放的是二进制的数据,这时再用二进制读取文件内容便可以明白所存存放的数据。
我们可以发现两个函数中所读取的元素,可以是整形,浮点型,结构体型等等。
#include<stdio.h> struct S { char name[20]; int age; double score; }; int main() { FILE* pf = fopen("test.dat","rw"); if (pf == NULL) { perror("fopen"); return 1; } struct S s = { "zhangsan",18,95.5 }; fwrite(&s,sizeof(s),1,pf);//写文件 fread(&s, sizeof(s), 1, pf);//读文件 printf("%s %d %f", s.name, s.age, s.score); fclose(pf); pf = NULL; return 0; }
两个返回值都是成功读到的元素的个数。
通讯录文件版本
这里我们在上次动态存储的通讯录的基础上再做调整。
主要做这几个调整:
1.在通讯录退出之前,将信息保存到文件中。
这里所保存到的文件名为“contact.dat”,
void Savecontact(Contact* pc) { FILE* pf = fopen("contact.dat","r"); if (pf == NULL) { perror("Savecontact::fopen"); return; } //写数据 int i = 0; for (i = 0; i <pc-> size; i++) { fwrite(pc->data+i, sizeof( peoInfo), 1, pf); } //关闭文件 fclose(pf); pf = NULL; printf("保 存 成 功 !\n"); }
注意保存到文件中的是二进制,我们输出到屏幕时利用fread读取文件。
2.加载文件信息到通讯录
该函数作用在打开文件的时候:
当然在加载时需检查此时的容量,需要之前写的加载容量的函数。
void loadcontact(Contact *pc) { //打开文件 FILE *pf= fopen("contact.dat", "rb"); if (pf == NULL) { perror("fopen"); return; } //读文件 peoInfo tmp = {0}; while (fread(&tmp,sizeof(peoInfo),1,pf)) { //检查容量 checkcapacity(pc); pc->data[pc->size] = tmp; pc->size++; } }
简单的通讯录 附带文件实现 - 代码片段 - Gitee.com
这是该代码的完整实现。
此就完成了文件的保存。
fseek函数 文件的随机读写
可以看出返回类型为 整形(如下图) 参数为(文件流,偏移量,起始位置)。
注意这里可以用ferror来判断。
这里说下起始位置:
函数参数里,最后一项即是起始位置,即你从哪里开始决定偏移,这个参数有三种写法,你可以写SEEK_ET 开头,SEEK_CUR 文件当前位置 SEEK_END文件末尾位置,这三种写法将决定你偏移到某位置时,偏移量的大小。
函数的应用:
int main() { FILE* pf = fopen("test.dat", "r");//文件放入abcdef if (pf == NULL) { return 1; } //读文件 int ch = fgetc(pf);//a printf("%c", ch); ch = fgetc(pf);//b printf("%c", ch); ch = fgetc(pf);//c printf("%c", ch); ch = fgetc(pf);//d printf("%c", ch); //这里想要读到 b fseek(pf, 1, SEEK_SET);//这里叫让文件从最开始往偏移1个位置 //fseek(pf, -3, SEEK_);//这里从当前位置往后偏移3个位置指向b ch = fgetc(pf); printf("%c", ch); //关闭文件 fclose(pf); pf=NULL; return 0; }
这里偏移几个,往前偏移,就是-几个,往后偏移,就是几个。
ftell函数
long int ftell(FILE *stream);
返回值为整形,参数为文件流。
函数作用是返回指针相对于起始位置的偏移量。
int main() { FILE* pf = fopen("test.dat", "r");//文件放入abcdef if (pf == NULL) { return 1; } //读文件 int ch = fgetc(pf);//a printf("%c", ch); ch = fgetc(pf);//b printf("%c", ch); ch = fgetc(pf);//c printf("%c", ch); ch = fgetc(pf);//d printf("%c", ch); printf("%d\n",ftell(pf));//返回四,当前位置与起始位置相差四个元素,偏移量为4。 //关闭文件 fclose(pf); pf=NULL; return 0; }
文本文件与二进制文件
数据文件被称为文本文件或者二进制文件。
数据在内存中以二进制的形式存储,去过不加转换的输出外村,就是二进制为文件。
如果要求在外村上以ASCLL码的形式存储,则需要再存储前转换,以ASCLL字符的形式存储的文件就是文本文件。
一个数据在内存中是如何存放的呢?
字符一律以ASCII形式存储,数值型数据既可以以ASCII码形式存储,也可以使用二进制存储。
文件读取结束的判定
被错误使用的feof,
文件读取结束的判定 feof
牢记:在文件读取过程中,不能使用feof函数的返回值直接判断是否结束
feof的作用是:当文件读取已经结束时候,判断读取结束的原因是否是遇到文件结束。这里的判断文件结束根据不同的函数,判断方式不同。
例如在fgtec中 判断返回是否为eof
在fgets函数中判断返回是否为NULL;
在二进制文件读取结束判断,判断返回值是小于读取的个数。
如:fread判断返回值是否小于实际要读的个数。
文件缓冲区
文件缓冲区即系统在读写程序时在内存中开辟的数据源与数据目标中间的一个用于保存完整数据内容的缓冲区域。 目前C语言使用的文件系统分为缓冲文件系统(标准I / O)和非缓冲文件系统(系统I / O)。 缓冲文件系统的特点是:在内存开辟一个“缓冲区”,为程序中的每一个文件使用,当执 行读文件的操作时,从磁盘文件将数据先读入内存“缓冲区”,装满后再从内存“缓冲区”依此读入接收的变量。
这里可以类比输入输出缓冲区。
最后实现一个代码 拷贝一个文件
int main() { //实现一个代码 //打开两个文件 被读的,被写的 FILE* pfread = fopen("text.txt", "r"); if (pfread == NULL) { fclose(pfread); pfread = NULL; return 1; } FILE* pfwrite = fopen("text.txt", "r"); int ch = 0; while ((ch = fgetc(pfread)) != EOF) { ch=fgetc(ch, pfread); fputc(ch, pfwrite); } fclose(pfwrite); pfwrite = NULL; return 0; }
一起加油!!