
目录
为了防止通讯录程序退出时数据消失,我们必须要将数据持久化,把数据存放到磁盘、存放到数据库,使用文件可以直接将数据放在电脑的硬盘上。
磁盘上的文件是文件。
从文件功能分类:程序文件、数据文件。
源程序文件(后缀为.c),目标文件(后缀为.obj),可执行程序(后缀为.exe)。
数据文件是程序运行时需要从中读取数据的文件,或者输出内容的文件。

文件名即文件标识,包含:文件路径+文件名主干+文件后缀
例如:
C:\数学建模\数学模型作业.docx

被使用的文件在内存中开辟了文件信息区,存放文件的名字、状态、当前位置等信息,这些信息保存在结构体变量中,结构体类型取名FILE。

不同的C编译器的FILE类型包含的内容大同小异:
- struct _iobuf {
- char *_ptr;
- int _cnt;
- char *_base;
- int _flag;
- int _file;
- int _charbuf;
- int _bufsiz;
- char *_tmpfname;
- };
- typedef struct _iobuf FILE;
-
打开文件的时候,系统自动创建一个FILE结构的变量,并填充信息。
定义pf是一个指向FILE类型数据的指针变量,使pf指向某个文件的文件信息区,并访问文件。
编写程序时,打开文件的时候,返回一个FILE*指针变量指向该文件。
- //打开文件
- FILE* fopen(const char* filename, const char* mode);
- //关闭文件
- int fclose(FILE* stream);
mode代表文件的打开模式,打开方式如下:

代码展示:
- #include
- #include
- int main()
- {
- FILE* pFile;
- pFile = fopen("myfile.txt", "w");//打开文件
- if (pFile == NULL)
- {
- printf("%s\n", strerror(errno));
- return 1;
- }
- //写(输出)文件
- fputs("fopen example", pFile);
- //关闭文件
- fclose(pFile);
- pFile = NULL;
- return 0;
- }

| 功能 | 函数名 | 适用于 |
| 字符输入函数 | fgetc | 所以输入流 |
| 字符输出函数 | fputc | 所有输出流 |
| 文本行输入函数 | fgets | 所有输入流 |
| 文本行输出函数 | fputs | 所有输出流 |
| 格式化输入函数 | fscanf | 所有输入流 |
| 格式化输出函数 | fprintf | 所有输出流 |
| 二进制输入 | fread | 文件 |
| 二进制输出 | fwrite | 文件 |


文件的顺序读写库函数使用举例:
- #include
- #include
- int main()
- {
- FILE* pf = fopen("test.txt", "w");
- if (pf = NULL)
- {
- printf("5s\n", strerror(errno));
- return 1;
- }
- //写文件
- char i = 0;
- for (i = 'a'; i <= 'z'; i++)
- {
- fputs(i, pf);
- }
- //关闭文件
- fclose(pf);
- pf = NULL;
- return 0;
- }
- //读一个字符
- int main()
- {
- FILE* pf = fopen("test.txt", "r");
- if (pf == NULL)
- {
- printf("%s\n", strerror(errno));
- return 1;
- }
- //读文件
- char ch = 0;
- while ((ch = fgetc(pf)) != EOF)
- {
- printf("%c\n", ch);
- }
- //关闭文件
- fclose(pf);
- pf = NULL;
- return 0;
- }
- //写一行数据
- int main()
- {
- FILE* pf = fopen("test.txt", "w");
- if (pf == NULL)
- {
- printf("%s\n", strerror(errno));
- return 1;
- }
- //写一行数据
- fputs("get money\n", pf);
- fputs("get meney\n", pf);
- //关闭文件
- fclose(pf);
- pf = NULL;
- return 0;
- }
- //读一行数据
- int main()
- {
- FILE* pf = fopen("test.txt", pf);
- if (pf == NULL)
- {
- perror("fopen");
- return 1;
- }
- char arr[20];
- fgets(arr, 20, pf);
- printf("%s\n", arr);
- //关闭文件
- fclose(pf);
- pf = NULL;
- return 0;
- }
- //格式化输入输出
- struct S
- {
- char arr[20];
- int age;
- float score;
- };
- struct S s = { 0 };
- int main()
- {
- FILE* pf = fopen("test.txt", "r");
- if(pf==NULL)
- {
- perror("fopen");
- return 1;
- }
- fscanf(pf, "%s %d %f", s.arr, &(s.age), &(s.score));
- fprintf(stdout, "%s %d %s", s.arr, s.age, s.score);
- fclose(pf);
- pf = NULL;
- return 0;
- }
- //以二进制形式输入输出
- int main()
- {
- struct S s = { 0 };
- FILE* pf = fopen("test.txt", "rb");
- if (pf = NULL)
- {
- perror(pf);
- return 1;
- }
- //二进制方式读
- fread(&s, sizeof(struct S), 1, pf);
- printf("%s %d %f\n", s.arr, s.age, s.score);
- fclose(pf);
- pf = NULL;
- return 0;
- }
- int main()
- {
- struct S s = { "sunlang",25,50.f };
- FILE* pf = fopen("test.txt", "wb");
- if (pf == NULL)
- {
- perror("fopen");
- return 1;
- }
- fwrite(&s, sizeof(struct S), 1, pf);
- fclose(pf);
- pf = NULL;
- return 0;
- }
scanf/fscanf/sscanf与printf/fprintf/sprintf的对比:
scanf是针对标准输入的格式化输入语句
printf是针对标准输出的格式化输出语句
fscanf是针对所有输入流的格式化输入语句
fprintf是针对所有输出流的格式化输出语句
sscanf是从一个字符串中转化出一个格式化的数据
sprinf是把一个格式化的数据转化成字符串
- //sscanf与sprintf的举例:
- struct S
- {
- char arr[10];
- int age;
- float score;
- };
- int main()
- {
- struct S s = { "zhangsan",20,55.5f };
- struct S tmp = { 0 };
- char a[100] = { 0 };
- //把s中的格式化数据转化成字符串放到a中
- sprintf(a, "%s %d %f", s.arr, s.age, s.score);
- //从字符串a中获取一个格式化的数据到tmp中
- sscnaf(a, "%s %d %f", tmp.arr, &(tmp.age), tmp.score);
- return 0;
- }
根据文件指针的位置和偏移量来定位文件指针
int fseek ( FILE * stream, long int offset, int origin );

使用举例:
- int main()
- {
- FILE* pFile;
- pFile = fopen("example.txt", "wb");
- fputs("This is an apple.", pFile);
- fseek(pFile, 9, SEEK_SET);
- fputs("sam", pFile);
- fclose(pFile);
- return 0;
- }
返回文件指针相对于起始位置的偏移量
long int ftell ( FILE * stream );
使用举例:
- int main()
- {
- FILE* pFile;
- long size;
- pFile = fopen("myfile.txt", "rb");
- if (pFile == NULL)
- {
- perror("Error opening file");
- }
- else
- {
- fseek(pFile, 0, SEEK_END);
- size = ftell(pFile);
- fclose(pFile);
- printf("Size of myfile.txt:%ld bytes.\n", size);
- }
- return 0;
- }
让文件指针的位置回到文件的起始位置
void rewind ( FILE * stream );
使用举例:
- #include
-
- int main ()
- {
- int n;
- FILE * pFile;
- char buffer [27];
-
- pFile = fopen ("myfile.txt","w+");
- for ( n='A' ; n<='Z' ; n++)
- fputc ( n, pFile);
- rewind (pFile);
- fread (buffer,1,26,pFile);
- fclose (pFile);
- buffer[26]='\0';
- puts (buffer);
- return 0;
- }
二进制文件:数据在内存中以二进制的形式存储,不加转换地输出到外存
文本文件:需要在存储前转换,以ASCII字符的形式存储的文件
字符用ASCII形式存储,数值型数据用ASCII形式或二进制形式存储。

例子:
- int main()
- {
- int a = 10000;
- FILE* pf = fopen("text.txt", "wb");
- fwrite(&a, 4, 1, pf);
- fclose(pf);
- pf = NULL;
- return 0;
- }
feof函数:表示在文件读取结束的时候,文件结束的原因:是读取失败,还是遇到文件结尾。
判断文件读取是否结束:fgetc判断是否为EOF;fgets判断返回值是否小于实际要读的个数。
二进制文件读取结束判断:返回值是否小于实际要读的个数,fread判断返回值是否小于实际要读的个数。
案例说明:
判断文本文件读取结束:
- #include
- int main(void)
- {
- int c;
- FILE* fp = fopen("test.txt", "r");
- if (!fp) {
- perror("File opening failed");
- return EXIT_FAILURE;
- }
- while ((c = fgetc(fp)) != EOF)
- {
- putchar(c);
- }
- if (ferror(fp))
- puts("I/O error when reading");
- else if (feof(fp))
- puts("End of file reached successfully");
- fclose(fp);
- }
判断二进制文件读取结束:
- enum { SIZE = 5 };
- int main(void)
- {
- double a[SIZE] = { 1.,2.,3.,4.,5. };
- FILE* fp = fopen("test.bin", "wb");
- fwrite(a, sizeof * a, SIZE, fp);
- fclose(fp);
- double b[SIZE];
- fp = fopen("test.bin", "rb");
- size_t ret_code = fread(b, sizeof * b, SIZE, fp);
- if (ret_code == SIZE) {
- puts("Array read successfully, contents: ");
- for (int n = 0; n < SIZE; ++n) printf("%f ", b[n]);
- putchar('\n');
- }
- else {
- if (feof(fp))
- printf("Error reading test.bin: unexpected end of file\n");
- else if (ferror(fp)) {
- perror("Error reading test.bin");
- }
- }
- fclose(fp);
- }
因为有缓冲区的存在,C语言在操作文件的时候,需要做刷新缓冲区或者在文件中操作结束时的时候关闭文件。

- #include
- int main()
- {
- FILE* pf = fopen("test.txt", "w");
- fputs("abcdef", pf);
- printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n");
- Sleep(10000);
- printf("刷新缓冲区\n");
- fflush(pf);
- printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n");
- Sleep(10000);
- fclose(pf);
- pf = NULL;
- return 0;
- }

本次分享到此结束,后续会有不断更新,不要忘记一键三连噢~