进阶:文件操作"/>
一、C语言进阶:文件操作
1 文件操作
1.1 文件的输入输出
输出:使用printf()
和命令行重定向>
实现文件输出;
输入:使用scanf()
和命令行重定向<
实现文件输入。
#include <stdio.h>
//printf() 写入文件 ./a.out > hello.txt
//scanf() 从文件读 ./a.out < hello.txt
int main(){char name[20];scanf("%s",name);printf("Hello %s!\n",name);
}
1.2 文件打开fopen()
和关闭fclose()
fopen()
函数原型:
FILE *fopen(char restrict *filename, char restrict *mode);
restrict C99标准才引进的,属于类型修饰符,表示修饰的这块内存空间只能被这个指针引用和修改,除此之外别无他法。
如果文件顺利打开,则返回值是指向这个文件流的文件指针,如果文件打开失败,返回NULL。
- filename:需要打开的文件
- mode:打开方式
mode的几种类型
1、r: 读
2、w: 写
3、a: 追加
4、+: 读或写,配合r、w、a使用
5、t: 文本文件
6、b: 二进制文件
注:a只能追加不能修改,w会把文件清空,r+读写方式可以修改文件原有内容。
fclose()
函数原型:
int flcose(FILE* stream);
stream: 函数指针
返回值:成功返回0,否则返回-1
1.3 文本读写fprintf()
和fscanf()
- 函数原型
int fprintf(FILE *stream, char *format, argument...);
int fscanf(FILE *stream, char *format, argument... );
fprintf()/fscanf()
与printf()/scanf()
使用非常相似,区别在于fprintf()/fscanf()
第一个参数stream
是文件描述符。
- 实例:
#include <stdio.h>
int main(){char name[20];fscanf(stdin,"%s",name); //stdin标准读,从终端读fprintf(stdout,"Hello %s!\n",name); //stdout标准写,向终端写
}
- 实例:学生信息的读入读出
#include <stdio.h>
typedef struct{char name[20];int age;float score;
} Stu;
int main(){FILE* pfile = fopen("./student","r");if(NULL == pfile){printf("file is not exited!\n");return 1;}int n;fscanf(pfile,"%d",&n);Stu s[n];for(int i = 0;i < n;++i){fscanf(pfile,"%s%d%f",&s[i].name,&s[i].age,&s[i].score);}fclose(pfile);pfile = NULL;FILE* pfile2 = fopen("./student2","w");if(NULL == pfile2){printf("file ./student2 is not exited!\n");return 1;}for(int i = 0;i < n;++i){fprintf(pfile2,"%s %d %.2f\n",s[i].name,s[i].age,s[i].score);}fclose(pfile2);pfile2 = NULL;
}
- 学生信息管理: 采用
fprintf()
和fscanf()
实现增删查改
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
typedef struct{char name[20];int age;float score;
} Stu;
bool Load(const char* path,Stu* s,int* n){FILE* file = fopen(path,"r");if(NULL == file){printf("file is not exited!\n");return false;}int m;fscanf(file,"%d",&m);*n = m;for(int i = 0;i < m;++i){fscanf(file,"%s%d%f",&s[i].name,&s[i].age,&s[i].score);}fclose(file);file = NULL;return true;
}
void ShowStudents(Stu* s,int n){for(int i = 0;i < n;++i){printf("%s %d %f\n",s[i].name,s[i].age,s[i].score);}
}
void SaveStudents(const char* path,Stu* s,int* n){FILE* file = fopen(path,"w");if(NULL == file){printf("file is not exited!\n");return;}fprintf(file,"%d\n",*n);for(int i = 0;i < *n;++i){fprintf(file,"%s %d %f\n",s[i].name,s[i].age,s[i].score);}fclose(file);file = NULL;
}
void Register(const char* path,Stu* s,int* n){int before = *n;printf("请输入录入学生个数:");int append_num;scanf("%d",&append_num);*n += append_num;printf("请依次输入学生姓名,年龄和成绩:\n");for(int i = before;i < *n;++i){scanf("%s%d%f",&s[i].name,&s[i].age,&s[i].score);}SaveStudents(path,s,n);
}
int cmp(const void* a,const void* b){return ((Stu*)(a))->score < ((Stu*)(b))->score?1:-1;
}
void SortStudents(Stu* s,int n){qsort(s,n,sizeof(Stu),cmp);ShowStudents(s,n);
}
void SearchStudents(Stu* s,int n){printf("请输入学生姓名:");char name[20];scanf("%s",name);bool found = false;for(int i = 0;i < n;++i){if(strcmp(name,s[i].name) == 0){found = true;printf("查询结果:%s %d %f\n",s[i].name,s[i].age,s[i].score);}}if(!found){printf("查无此人!\n");}
}
void DeleteStudents(const char* path,Stu* s,int* n){printf("请输入学生姓名:");char name[20];scanf("%s",name);bool found = false;for(int i = 0;i < *n;++i){if(strcmp(name,s[i].name) == 0){found = true;for(int j = i+1;j < *n;++j){s[i++] = s[j];}*n -= 1;printf("删除成功!\n");break;}}if(!found){printf("查无此人!\n");return;}SaveStudents(path,s,n);
}void ModifyStudents(const void* path,Stu* s,int n){printf("请输入学生姓名:");char name[20];scanf("%s",name);bool found = false;for(int i = 0;i < n;++i){if(strcmp(name,s[i].name) == 0){found = true;printf("请依次输入修改后的信息:姓名 年龄 成绩\n");scanf("%s%d%f",&s[i].name,&s[i].age,&s[i].score);break;}}if(!found){printf("查无此人!\n");return;}SaveStudents(path,s,&n);
}
int main(){const char* data = "./student.txt";Stu s[10];int n;if(Load(data,s,&n)){printf("已经加载%d名学生信息\n",n); }while(true){printf("功能列表:\n");printf("1.查看所有学生信息\n");printf("2.录入学生信息\n");printf("3.按成绩排序\n");printf("4.查询学生信息\n");printf("5.删除学生信息\n");printf("6.修改学生信息 \n");printf("0.退出\n");int num;scanf("%d",&num);switch(num){case 1: ShowStudents(s,n);break;case 2:Register(data,s,&n);break;case 3:SortStudents(s,n);break;case 4:SearchStudents(s,n);break;case 5:DeleteStudents(data,s,&n);break;case 6:ModifyStudents(data,s,n);break;case 0:return 0;}}
}
1.4 二进制读和写:fread()和fwrite()
- 函数原型
size_t fread(void *ptr, size_t size, size_t count, FILE* stream);
size_t fwrite(void *ptr, size_t size, size_t count, FILE* stream);
ptr: 一个指针,在fread()
中是从文件里读入的数据存放的地址;在fwrite()
中是写入到文件里的数据存放的地址。
ptr | 指针,在fread() 中是从文件里读入的数据存放的地址;在fwrite() 中是写入到文件里的数据存放的地址 |
---|---|
size | 每次要读写的字节数 |
count | 读写的次数 |
stream | 文件指针 |
- 返回值:成功读取/写入的字节数
- 实例:
fread()和fwrite()
实现文件读和写
#include <stdio.h>
#include <string.h>
int main(){FILE* fp= fopen("./hello.txt","rw");char str[] = "Hello World";fwrite(str,sizeof(str),1,fp);char str1[20];fread(str1,sizeof(str1),1,fp);printf("%s\n",str1);
}
- 学生信息管理: 采用
fread()和fwrite()
实现增删查改
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
typedef struct{char name[20];int age;float score;
} Stu;
bool Load(const char* path,Stu* s,int* n){FILE* file = fopen(path,"rb");if(NULL == file){printf("file is not exited!\n");return false;}int m;fread(&m,sizeof(m),1,file);//fscanf(file,"%d",&m);*n = m;fread(s,sizeof(Stu),m,file);/*for(int i = 0;i < m;++i){fscanf(file,"%s%d%f",&s[i].name,&s[i].age,&s[i].score);}*/fclose(file);file = NULL;return true;
}
void ShowStudents(Stu* s,int n){for(int i = 0;i < n;++i){printf("%s %d %f\n",s[i].name,s[i].age,s[i].score);}
}
void SaveStudents(const char* path,Stu* s,int n){FILE* file = fopen(path,"wb");if(NULL == file){printf("file is not exited!\n");return;}fwrite(&n,sizeof(n),1,file);//fprintf(file,"%d\n",*n);fwrite(s,sizeof(Stu),n,file);/*for(int i = 0;i < *n;++i){fprintf(file,"%s %d %f\n",s[i].name,s[i].age,s[i].score);}*/fclose(file);file = NULL;
}
void Register(const char* path,Stu* s,int* n){int before = *n;printf("请输入录入学生个数:");int append_num;scanf("%d",&append_num);*n += append_num;printf("请依次输入学生姓名,年龄和成绩:\n");for(int i = before;i < *n;++i){scanf("%s%d%f",&s[i].name,&s[i].age,&s[i].score);}SaveStudents(path,s,*n);
}
int cmp(const void* a,const void* b){return ((Stu*)(a))->score < ((Stu*)(b))->score?1:-1;
}
void SortStudents(Stu* s,int n){qsort(s,n,sizeof(Stu),cmp);ShowStudents(s,n);
}
void SearchStudents(Stu* s,int n){printf("请输入学生姓名:");char name[20];scanf("%s",name);bool found = false;for(int i = 0;i < n;++i){if(strcmp(name,s[i].name) == 0){found = true;printf("查询结果:%s %d %f\n",s[i].name,s[i].age,s[i].score);}}if(!found){printf("查无此人!\n");}
}
void DeleteStudents(const char* path,Stu* s,int* n){printf("请输入学生姓名:");char name[20];scanf("%s",name);bool found = false;for(int i = 0;i < *n;++i){if(strcmp(name,s[i].name) == 0){found = true;for(int j = i+1;j < *n;++j){s[i++] = s[j];}*n -= 1;printf("删除成功!\n");break;}}if(!found){printf("查无此人!\n");return;}SaveStudents(path,s,*n);
}void ModifyStudents(const void* path,Stu* s,int n){printf("请输入学生姓名:");char name[20];scanf("%s",name);bool found = false;for(int i = 0;i < n;++i){if(strcmp(name,s[i].name) == 0){found = true;printf("请依次输入修改后的信息:姓名 年龄 成绩\n");scanf("%s%d%f",&s[i].name,&s[i].age,&s[i].score);break;}}if(!found){printf("查无此人!\n");return;}SaveStudents(path,s,n);
}
int main(){const char* data = "./student2.dat";Stu s[10];int n;if(Load(data,s,&n)){printf("已经加载%d名学生信息\n",n); }while(true){printf("功能列表:\n");printf("1.查看所有学生信息\n");printf("2.录入学生信息\n");printf("3.按成绩排序\n");printf("4.查询学生信息\n");printf("5.删除学生信息\n");printf("6.修改学生信息 \n");printf("0.退出\n");int num;scanf("%d",&num);switch(num){case 1: ShowStudents(s,n);break;case 2:Register(data,s,&n);break;case 3:SortStudents(s,n);break;case 4:SearchStudents(s,n);break;case 5:DeleteStudents(data,s,&n);break;case 6:ModifyStudents(data,s,n);break;case 0:return 0;}}
}
注:读取文件须为二进制文件.dat
1.5 文件定位:ftell()
和fseek()
- 函数原型
// 获取位置
long ftell(FILE* stream);
// 设置位置
int fseek(FILE* stream,long offset,int whence);
- 参数
stream | 文件指针 |
---|---|
offset | 基于起始点的偏移量 |
whence | 起始点 |
whence的集中状态及含义:
whence | 数值 | 含义 |
---|---|---|
SEEK_SET | 0 | 从头开始 |
SEEK_CUR | 1 | 从当前开始 |
SEEK_END | 2 | 从结束开始 |
- 返回值
ftell()返回基于文件开头的偏移字节数。 - 实例:计算文件大小
#include <stdio.h>
int main() {FILE* fp = fopen("hello.txt","r");if(fp) {fseek(fp,0,SEEK_END);//设置指针为最后位置,便宜0字节long size = ftell(fp); //ftell()返回基于文件开头的偏移字节数。printf("大小为%ldB\n",size);}
}
1.6 文件结尾判断feof()
- 函数原型
int feof(FILE* stream);
- 参数
stream
文件指针 - 返回值
若指针指向文件结尾,返回一个真值,否则返回非真值。
1.7 返回开头rewind()
- 函数原型
void rewind(FILE* stream);
- 参数
stream
文件指针 - 实例
#include <stdio.h>
int main() {FILE* fp = fopen("hello.txt","r");fseek(fp,0,SEEK_END);long len = ftell(fp);printf("%d\n",len);rewind(fp);len = ftell(fp);printf("%d\n",len);
}
13
0
1.8 清空数据流
- 函数原型
void fflush(FILE* stream);
- 参数
stream
文件指针 - 举例
fflush(fp); // 清空文件流
更多推荐
一、C语言进阶:文件操作
发布评论