一、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_SET0从头开始
SEEK_CUR1从当前开始
SEEK_END2从结束开始
  • 返回值
    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);        // 清空文件流
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值