1.前言
在前面我们写到过文件的打开与关闭用到了函数主要是fopen函数,参数是文件的文件名和打开方式,文件关闭函数fclose,参数是流,我们还讲到过流,今天我们讲解一些写文件与读文件函数以及对通讯录的改进还有一些文件的其他函数。
2.写文件函数与读文件函数
功能 | 函数名 | 适用于 |
字符输入函数 | fgetc | 所有输入流 |
字符输出函数 | fputc | 所有输出流 |
文本行输入函数 | fgets | 所有输入流 |
文本行输出函数 | fputs | 所有输出流 |
格式化输入函数 | fscanf | 所有输入流 |
格式化输出函数 | fprintf | 所有输出流 |
二进制输入 | fread | 文件 |
二进制输出 | fwrite | 文件 |
2.1fputc函数
我们在cplusplus网中 fputc看到它的第一个参数是int chararcter,这个含义是想要存储的字符信息,第二个参数是流在这里指fopen函数的返回值,fputc函数是将chararcter存入文件中,我们写一个代码将abcdef放到文件中,详细代码如下:
#include<stdio.h> int main() { FILE* pf = fopen("data.txt", "w"); if (pf == NULL) { perror("fopen"); return 1; } int i; for (i = 'a'; i <= 'f'; i++) { fputc(i, pf); } fclose(pf); pf = NULL; return 0; }
我们运行后打开文件data.txt
我们可以看到abcdef已经写到了文件中 先打开文件,再利用循环利用写入字符函数fputc进行信息的存储。
2.2fgetc函数
我们进入cplusplus网站fgetc我们看到它的参数是流,返回值是int类型,hfgetc函数的作用是读取文件的一个字符,我们写一个代码读取fputc函数存在文件的信息,详细代码如下:
#include<stdio.h> int main() { FILE* pf = fopen("data.txt", "r"); if (pf == NULL) { perror("fopen"); return 1; } int i,ch; for (i = 'a'; i <= 'f'; i++) { ch = fgetc(pf); printf("%c", ch); } fclose(pf); pf = NULL; return 0; }
我们运行结果如下:
2.3fputs函数
我们进入cplusplus网站fputs,函数的第一个参数是const char *str是将str中的内容传到文件中,第二个参数是流 ,返回类型是int,fputs函数的作用是将字符串传到文件中,我们写一个代码将字符串abcdefgh传到文件中,详细代码如下:
#include<stdio.h> int main() { FILE* pf = fopen("data.txt", "w"); if (pf == NULL) { perror("fopen"); return 1; } char arr[] = "abcdefgh"; fputs(arr,pf); fclose(pf); pf = NULL; return 0; }
运行后我们打开data.txt文件 可以看到
我们如果再次将arr内容改为ccc运行后打开data.txt文件
我们还可以看到打开文件后光标都在最前面,而且原来的信息也没有了,那我们是不是可以理解为写入文件是将原来的文件的内容覆盖, 然后写入信息。
2.4fgets函数
我们进入cplusplus网站fgets看到它的第一个参数是char *str是读取文件后存放在程序的变量,第二个参数int num是在文件中读取几个字符+1,第三个参数是流,返回值是char*,例如我们想读取文件中的abcdefg,详细代码如下:
#include<stdio.h> int main() { FILE* pf = fopen("data.txt", "r"); if (pf == NULL) { perror("fopen"); return 1; } char arr[1006] ; char* p = arr; p = fgets(p, 7, pf); printf("%s", arr); fclose(pf); pf = NULL; return 0; }
我们运行后可以看到
对于为什么是7,原因很简单,fgets函数会在最后将数组的第num个位置转化为’\0‘,我们进入调试可以看到
2.5fprintf函数
我们进入 cplusplus网站fprintf 查看fprintf函数的参数,看到这个函数你是不是会想到printf函数,我们同样查看printf函数的参数
我们可以看到他们两个只差流这个参数,fprintf函数是格式化输入文件,我们写一个代码来展示一下这个函数的功能,代码如下:
#include<stdio.h> struct num { float s; int i; char s1[10]; }S; int main(){ FILE* pf = fopen("data.txt", "w"); if (pf == NULL) { perror("fopen"); return 1; } S = { 1.23f,10,"wo" }; fprintf(pf, "%f-%d-%s", S.s, S.i, S.s1); fclose(pf); pf = NULL; return 0; }
我们运行程序后打开data.txt文件,可以看到
同样我们可以理解为将结构体S里面的内容,以 - - 的形式输出到文件里。
2.6fscanf函数
我们进入cplusplus网站fscanf查看fscanf函数的参数,看到fscanf函数我们很容易想到scanf函数,我们同样进入cplusplus网站查看scanf函数的参数,
我们可以看到这两个函数的参数只差了一个流, fscanf函数是将文件中有格式的信息储存在程序中定义的变量里,我们利用fprintf函数储存在文件的内容来初始化结构体S,详细代码如下:
#include<stdio.h> struct num { float s; int i; char s1[10]; }S; int main(){ FILE* pf = fopen("data.txt", "r"); if (pf == NULL) { perror("fopen"); return 1; } fscanf(pf,"%f-%d-%s", &S.s, &S.i, &S.s1); printf("%f %d %s", S.s, S.i, S.s1); fclose(pf); pf = NULL; return 0; }
我们运行代码,可以看到
2.7sprintf函数与sscanf函数
sprintf函数是将数据以字符的形式存在s中, sscanf函数是将s的数据以字符的形式存在程序定义的变量中,我们写一个程序,代码如下:
#include<stdio.h> struct num { int i; char arr; float f; }; int main() { struct num s = { 10,'c',1.2f}; char arr[100] = { 0 }; sprintf(arr, "%d%c%f", s.i, s.arr, s.f); struct num tmp = { 0 }; sscanf(arr, "%d%c%f", &tmp.i, &tmp.arr, &tmp.f); printf("%d %c %f", tmp.i, tmp.arr, tmp.f); return 0; }
运行结果如下:
2.8fwrite函数
我们进入cplusplus网站fwrite的参数第一个参数是const void *ptr是指向的数据的地址,第二个参数size_t size是单个数据所占据的字节,第三个参数size_t count是要写进文件几个数据,第四个参数是流,特别注意这是以二进制的形式储存在文件中 ,我么们写一个代码展示一下函数的功能,代码如下:
#include<stdio.h> struct num { int i; char arr[10]; char brr[10]; }; int main() { FILE* pf = fopen("data.txt", "w"); if (pf == NULL) { perror("fopen"); return 1; } struct num s = { 1,"abcd","efg" }; fwrite(&s, sizeof(struct num), 1, pf); fclose(pf); pf = NULL; return 0; }
我们运行代码后,打开data.txt文件可以看到:
由于是二进制的形式存储,所以有些信息我们不能识别。
2.9fread函数
我们进入cplusplus网站看fread的参数一个参数是const void *ptr是要读取文件信息保存到,第二个参数size_t size是单个数据所占据的字节,第三个参数size_t count是要写进文件几个数据,第四个参数是流,我们读取上个函数的内容,代码如下:
#include<stdio.h> struct num { int i; char arr[10]; char brr[10]; }; int main() { FILE* pf = fopen("data.txt", "r "); if (pf == NULL) { perror("fopen"); return 1; } struct num s; fread(&s, sizeof(struct num), 1, pf); printf("%d\n%s\n%s", s.i, s.arr, s.brr); fclose(pf); pf = NULL; return 0; }
运行程序后可以看到
3.通讯录的改进
在程序中加入函数
void init(Struct* pc) { assert(pc); FILE* pf = fopen("data.txt", "r"); if (pf == NULL) { perror("fopen"); return; } while (fread(pc->arr + pc->i , sizeof(struct xinxi), 1, pf)) { pc->i++; addnum(pc); } fclose(pf); pf = NULL; }
以及函数
void save(Struct* pc) { assert(pc); FILE* pf = fopen("data.txt", "w"); if (pf == NULL) { perror("fclose"); return; } int i; for (i = 0; i < pc->i; i++) { fwrite(pc->arr + i, sizeof(struct xinxi), 1, pf); } fclose(pf); pf = NULL; }
4.文件的随机读写
4.1fseek函数
根据文件指针的位置和偏移量来定位文件指针,第一个参数是流,第二个参数是偏移量v,第三个参数是相对位置,SEEK_SET是对于最初的位置,SEEK_CUR是对现在的位置,SEEK_END是对最后一位的位置。
我们写一个代码,如下:
#include<stdio.h> int main() { FILE* pf = fopen("data.txt", "r "); if (pf == NULL) { perror("fopen"); return 1; } int ch; ch = fgetc(pf); printf("%c", ch);//a ch = fgetc(pf); printf("%c", ch);//b ch = fgetc(pf); printf("%c", ch);//c fseek(pf, -3, SEEK_CUR); ch = fgetc(pf); printf("%c", ch);//a fclose(pf); pf = NULL; return 0; }
运行后为
这个函数有一定的局限性,我们必须对文件的内容非常熟悉,否则不容易输出我们想要的值。
4.2ftell函数
这个函数是计算相对于初始位置的偏移量 ,我们可以写一个代码,如下:
#include<stdio.h> int main() { FILE* pf = fopen("data.txt", "r "); if (pf == NULL) { perror("fopen"); return 1; } fseek(pf, 0, SEEK_END); size_t sz = ftell(pf); printf("%d", sz); fclose(pf); pf = NULL; return 0; }
运行结果为
4.3rewind函数
函数的功能是让指针指向初始位置,我们写一个代码,来展示一下它的功能:
#include<stdio.h> int main() { FILE* pf = fopen("data.txt", "r "); if (pf == NULL) { perror("fopen"); return 1; } fseek(pf, -1, SEEK_END); int ch; ch = fgetc(pf); printf("%c\n", ch); rewind(pf); ch = fgetc(pf); printf("%c\n", ch); fclose(pf); pf = NULL; return 0; }
运行结果为
文件的内容为
5.总结
今天主要包括将数据传入文件的函数,以及将文件中的内容传到程序中的函数,还有一些对于文件中的指针以及偏移量的函数fseek函数,ftell函数,rewind函数的讲解,异界对通讯录的改造.今天的内容就结束了。