C语言文件管理
文件管理常常作为被忽略知识,但却十分重要,在某些场景缺‘它’不可
文章目录
1.文件管理有啥用?
- 我们在写通讯录时候就知道,运行程序时,先输入各种数据,然后调整…,但是当我们结束这个程序时,我们会发现之前存储的那些数据都不在了,然后又要重新输入…,原因是当我们写入数据时,数据保存在内存中,但程序结束后,内存会被电脑回收,数据也就跟着消失了。
- 将数据存放在文件中就很好解决这个问题,我们都知道文件数据是存放在磁盘文件或数据库中的,这样当程序运行结束后数据也就不会消失了,因此使用文件将数据直接存放在电脑的硬盘上,使得数据的持久化。
2.什么是文件
- 磁盘上的文件是文件,文件类型很多,但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件。
2.1程序文件
- 程序文件包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)等等。
2.2数据文件
- 除了程序文件存放程序外,还有数据文件,存放数据,作为程序运行时读取写入的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。
- 在以前各章所处理数据的输入输出都是以终端为对象的,比如键盘输入数据,运行结果显示到显示器上,而现在将数据存到文件中,这时候文件就像终端一样,之前键盘输入数据变成从文件中拿数据,之前数据显示在屏幕上变成将数据存到文件中。
2.3文件名称
- 我们每个人有唯一身份证来证明自己独特存在,同理一个文件要有一个唯一的文件标识,以便用户识别和引用。
文件名包含3部分:文件路径+文件名主干+文件后缀
3.文件的打开和关闭
3.1文件指针
哎呀,又没见过我不会,好难,我不学了!不要这样,一口吃不成胖子,慢慢吃,就一点也不难。
- 我们生活中从水壶灌水取水,首先打开水壶,然后在进行取水灌水操作,用完后关闭水壶。同理,使用文件数据拿放时,也得先打开文件,然后进行操作,最后关闭文件。
- 每个被使用的文件都会在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是由系统声明的,取名FILE,由FILE定义指针就是文件指针,指向文件信息区地址。
- 简单说就是:使用文件时会创建一个文件指针来存放文件一些状态信息,就像我们创建一个变量时可以在创建一个指针存放其地址一样。
我们可以创建一个FILE*的指针变量:
FILE* pf; /文件指针变量
定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联的文件。
- 和之前学的指针不能说很相似吧,只能说一模一样
3.2文件的打开和关闭
- 刚刚说过文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。
在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指针和文件的关系。ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件。cplusplus网站:fopen,fclose
- 常用读取模式:
代码实例:
#include <stdio.h>
int main ()
{
FILE * pFile; /创建文件指针,后面用来接受
/打开文件
pFile = fopen ("myfile.txt","w");
/文件操作
if (pFile!=NULL) /如果打开失败返回空
{
fputs ("fopen example",pFile); /输出数据到文件中
/关闭文件
fclose (pFile);
}
else
{
perror("fopen:");/错误信息打印,介绍如下,fopen是错误提示词
}
return 0;
}
4.文件顺序读写
- 常用读写函数如下,在cplusplus网站可以详细学习,我们要学习它的参数,返回值和运用,接下来我会详细演示读写函数。
4.1 fputc(),fputc()函数
fput()和fgetc()函数作为单个字符输入输出函数,介绍如下:
代码演示:
int main()
{
FILE* pfile; /创建文件指针变量,用于接受fopen返回值
pfile = fopen("test.txt", "w"); /未写全文件名称,这时会默认在源文件地址下创建
if (NULL == pfile) /判断是否打开成功(如果没有会自动创建)
{
perror("fopen:"); /屏幕上报错
return;
}
fputc('a', pfile);
fputc('bc', pfile); /这样会在文件中写入什么呢?
fputc('d', pfile);
fclose(pfile);
pfile = NULL; /指针置空,防止非法访问
return 0;
}
实现效果
- fgetc()函数
代码演示:
int main()
{
FILE* pfile;
pfile = fopen("test.txt", "r"); /还是刚刚那个文件
if (NULL == pfile)
{
perror("fopen");
return;
}
int i = 0;
i = fgetc(pfile); /返回值是int型,用int变量接受
printf("%d ", i);
i = fgetc(pfile);
printf("%c ", i);
i = fgetc(pfile);
printf("%d ", i);
i = fgetc(pfile); /这时已经是文件末尾了,看看会输出什么
printf("%d ", i);
fclose(pfile);
pfile = NULL;
return 0;
}
实现效果
4.2 fputs(),fgets()函数
fgets()和fgets()作为行输入输出函数,介绍如下:
代码演示:
int main()
{
FILE* pfile;
/当再次在同一文件进行写入时,之前数据会被销毁,从新开始写入
pfile = fopen("test.txt", "w");
if (NULL == pfile)
{
perror("fopen");
return;
}
char* arr = "abcdefg";
fputs(arr, pfile);
arr = "\nabcd";/文件不会自动换行,要自己手动输入
fputs(arr, pfile);
fclose(pfile);
pfile = NULL;
return 0;
}
- fgets()函数
int main()
{
FILE* pfile;
pfile = fopen("test.txt", "r");
if (NULL == pfile)
{
perror("fopen");
return;
}
char ptr[20]="########";
/读一行,读xx个,若没有xx个则文件该行有多少个读多少个
fgets(ptr, 2, pfile);/无论读多少个实际读数都会少1字符,少那个会放\0
printf("%s", ptr);
fgets(ptr, 5, pfile);/读完一行后才会读下一行
printf("%s", ptr);
return 0;
}
4.3 fread()和fwrite()函数
fread(),fwrite()函数作为二进制输入输出(我们看不懂,电脑能看懂)函数,输入输出流只能是文件,用rb和wb,介绍如下:
代码演示:
/二进制写文件
struct S
{
char name[20];
int age;
float score;
};
int main()
{
struct S s = { "wangwu",18,99.5 };
FILE* pfile;
pfile = fopen("test.txt", "wb");
if (NULL == pfile)
{
perror("fopen");
return;
}
fwrite(&s, sizeof(s), 1, pfile);
fclose(pfile);
pfile = NULL;
return 0;
}
/二进制的读文件
struct S
{
char name[20];
int age;
float score;
};
int main()
{
struct S s = { 0 };
FILE* pfile = 0;
pfile = fopen("test.txt", "rb");
if (NULL == pfile)
{
perror("fopen");
return;
}
fread(&s, sizeof(s), 1, pfile);
printf("%s %d %f", s.name, s.age, s.score);
fclose(pfile);
pfile = NULL;
return 0;
}
4.4 fprintf()和fscanf()函数
- fprintf(),fscanf()是作为格式化输入输出(结构体)。
- fprintf,fscanf和我们之前学的printf和scanf是十分相似的,只是对象从键盘和屏幕变成了文件。介绍如下:
代码演示
/fprintf()函数
struct stu
{
char name[20];
int age;
float score;
};
int main()
{
struct stu s = { "wangwu",19,99.5f};
FILE* pfile;
pfile = fopen("test.txt", "w");
if (NULL == pfile)
{
perror("fopen");
return;
}
/和printf区别就是多了一个文件指针参数
fprintf(pfile,"%s %d %.1f", s.name, s.age, s.score);
fclose(pfile);
pfile = NULL;
return 0;
}
/fscanf()函数
struct stu
{
char name[20];
int age;
float score;
};
int main()
{
struct stu s = {0};
FILE* pfile;
pfile = fopen("test.txt", "r");
if (NULL == pfile)
{
perror("fopen");
return;
}
fscanf(pfile, "%s %d %f", s.name, &(s.age), &(s.score));
printf("%s %d %.1f", s.name, s.age, s.score);
fclose(pfile);
pfile = NULL;
return 0;
}
实现效果:
5.sscanf和sprintf函数
代码演示:
struct S
{
char name[10];
int age;
float score;
};
int main()
{
char arr[100] = { 0 };
struct S a = { "wangxu",18,99.5 };
struct S b = { 0 };
/将结构体转为字符串形式
sprintf(&arr, "%s ""%d ""%f", a.name, a.age, a.score);
printf("%s", arr);
/将arr中字符串转化为结构体形式
sscanf(&arr, "%s""%d""%f", b.name, &(b.age), &(b.score));
printf("\n%s ""%d ""%f", b.name, b.age, b.score);
return 0;
}
知识补充:
- fgetc,fputs…是所有输入/输出流,那能不能使用键盘将数据输入到文件,或者将数据打印到屏幕呢?答案是可以的:
- 我们只需要多加入这些流参数就可以实现:scanf(…)等价于fscanf(stdin,…) ,printf等价于fprintf(stdout, …)
代码展示:
/实现在键盘输入,在屏幕打印出来
int main()
{
int ch = fgetc(stdin);
fputc(ch, stdout);
return 0;
}
/实现在键盘输入,打印到文件
int main()
{
FILE* pfile;
pfile = fopen("test.txt", "w");
if (NULL == pfile)
{
perror("fopen");
return;
}
fputc(fgetc(stdin), pfile);
fclose(pfile);
pfile = NULL;
return 0;
}
/实现输入到文件变成输入到屏幕
struct stu
{
char name[20];
int age;
float score;
};
int main()
{
struct stu s = { "wangwu",19,99.5f };
FILE* pfile;
pfile = fopen("test.txt", "w");
if (NULL == pfile)
{
perror("fopen");
return;
}
/stdout使得原本输入到文件变为可输入到屏幕
fprintf(stdout, "%s %d %.1f", s.name, s.age, s.score);
fclose(pfile);
pfile = NULL;
return 0;
}
实现效果:
- 到这里本篇文件管理讲解就结束啦,下一篇将继续讲解接下来内容有:<文件的随机读写 > <文本文件和二进制文件 > <文件读取结束的判定 > <文件缓冲区>这四部分内容。
- 学习去,冲!!!