复习18年考研复试的时候,发现17年和18年均考查了C语言的文件读写,刚好自己也不太记得这一块了,干脆写一篇复习笔记。
fopen()函数
使用fopen()函数时,需要包括头文件
1 | include <stdio.h> |
- 如果希望接收 fopen() 的返回值,就需要定义一个 FILE 类型的指针。例如:
1 | FILE *fp = fopen("demo.txt", "r"); |
- 表示以“只读”方式打开当前目录下的 demo.txt 文件,并使 fp 指向该文件,这样就可以通过 fp 来操作 demo.txt。fp 通常被称为文件指针。
判断文件是否打开成功
打开文件出错时,fopen() 将返回一个空指针,也就是 NULL,我们可以利用这一点来判断文件是否打开成功。
1
2
3
4
5FILE *fp;
if( (fp=fopen("D:\\demo.txt","rb") == NULL ){
printf("Fail to open file!\n");
exit(0); //退出程序(结束程序)
}fopen()函数的打开方式
读写权限:
- “r”: 以“只读”方式打开文件。只允许读取,不允许写入。文件必须存在,否则打开失败。
- “w”: 以“写入”方式打开文件。如果文件不存在,那么创建一个新文件;如果文件存在,那么清空文件内容(相当于删除原文件,再创建一个新文件)。
- “a”: 以“追加”方式打开文件。如果文件不存在,那么创建一个新文件;如果文件存在,那么将写入的数据追加到文件的末尾(文件原有的内容保留)。
- “r+”: 以“读写”方式打开文件。既可以读取也可以写入,也就是随意更新文件。文件必须存在,否则打开失败。
- “w+”: 以“写入/更新”方式打开文件,相当于
w
和r+
叠加的效果。既可以读取也可以写入,也就是随意更新文件。如果文件不存在,那么创建一个新文件;如果文件存在,那么清空文件内容(相当于删除原文件,再创建一个新文件)。 - “a+”: 以“追加/更新”方式打开文件,相当于a和r+叠加的效果。既可以读取也可以写入,也就是随意更新文件。如果文件不存在,那么创建一个新文件;如果文件存在,那么将写入的数据追加到文件的末尾(文件原有的内容保留)。
读写方式:
- “t”: 文本文件。如果不写,默认为
"t"
。 - “b”: 二进制文件。
fclose()函数关闭方式
文件一旦使用完毕,应该用 fclose() 函数把文件关闭,以释放相关资源,避免数据丢失。fclose() 的用法为:
1
fclose(fp);
文件正常关闭时,fclose() 的返回值为0,如果返回非零值则表示有错误发生。
实例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int main() {
FILE *fp;
char str[N + 1];
//判断文件是否打开失败
if ( (fp = fopen("d:\\demo.txt", "rt")) == NULL ) {
puts("Fail to open file!");
exit(0);
}
//循环读取文件的每一行数据
while( fgets(str, N, fp) != NULL ) {
printf("%s", str);
}
//操作结束后关闭文件
fclose(fp);
return 0;
}fgets()函数
1
2
char *fgets(char *s, int size, FILE *stream);- 从 stream 流中读取 size 个字符存储到字符指针变量 s 所指向的内存空间。它的返回值是一个指针,指向字符串中第一个字符的地址。
- fgets()函数会从缓冲区中取出回车,并写入末尾
fputs()函数和fprintf()函数
1
2
3
4
5
6
7
8
9
10
11
12
13
int main() {
char *s="That's good news";
int i=617;
FILE *fp;
fp=fopen("test.dat", "w"); /*建立一个文字文件只写*/
fputs("Your score of TOEFL is",fp); /*向所建文件写入一串字符*/
fputc(':', fp); /*向所建文件写冒号:*/
fprintf(fp, "%d\n", i); /*向所建文件写一整型数*/
fprintf(fp, "%s", s); /*向所建文件写一字符串*/
fclose(fp);
}fscanf()函数
假设txt的文本内容为:
张三 18 1.74
即数据与数据之间用空格分隔开来,则读取函数为:
1
2
3
4while(!feof(fp)) {
fscanf(fp,"%s %d %lf",a,&b,&c);
//这里%s对应的a不需要加上取地址符号&,因为a为数组名称,其本身就表示该数组的首地址
}如果数据与数据之间用逗号分隔开来,在fscanf()函数中也要加入逗号
1
2
3
4while(!feof(fp)) {
fscanf(fp,"%s, %d, %lf",a,&b,&c);
//这里%s对应的a不需要加上取地址符号&,因为a为数组名称,其本身就表示该数组的首地址
}另一种判断是否到达文件末尾的方式为:
1
2int n = 0;
while(fscanf(in,"%s %d,",stu[n].name,&stu[n].x) != EOF) n++;从文件A.txt读取学生姓名和成绩,排序后写到B.txt文件中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
FILE *in,*out;
typedef struct {
int x;
char name[10];
}STU;
STU stu[100];
int cmp(const void *a,const void *b) {
return ((STU*)a)->x > ((STU*)b)->x ? -1:1;
}
int main() {
int n,i;
char name[10];
in = fopen("E:\\A.txt","r");
out = fopen("E:\\B.txt","w");
n = 0;
while(fscanf(in,"%s %d,",stu[n].name,&stu[n].x)!=EOF) n++;
qsort(stu,n,sizeof(STU),cmp);
for(i = 0; i < n - 1; i++)
fprintf(out,"%s %d, ",stu[i].name, stu[i].x);
fprintf(out,"%s %d",stu[i].name, stu[i].x); //不懂这里为什么要写作两行
fclose(in);
fclose(out);
return 0;
}