C语言文件提高

本文详细介绍了C语言中的文件相关概念,包括文本流和二进制流,以及文件的打开、关闭、读写等操作。重点讲解了字符、行和块读写函数的使用,还包括格式化和随机读写。通过实例展示了如何读写配置文件,提供了完整的代码示例。
摘要由CSDN通过智能技术生成

C语言文件提高

在这里插入图片描述

一、文件相关概念

1.文件的概念

在这里插入图片描述

2.流的概念

在这里插入图片描述

文本流

在这里插入图片描述

二进制流

在这里插入图片描述

二、文件的操作

1.文件流总览

在这里插入图片描述
在这里插入图片描述

2.文件指针

在这里插入图片描述
在这里插入图片描述

3.文件缓冲区

在这里插入图片描述

4.文件打开关闭

文件打开(fopen)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

文件关闭(fclose)

在这里插入图片描述

5.文件读写函数回顾

在这里插入图片描述

字符读写函数回顾
int fputc(int ch, FILE * stream);
功能:将ch转换为unsigned char后写入stream指定的文件中
参数:
	ch:需要写入文件的字符
	stream:文件指针
返回值:
	成功:成功写入文件的字符
	失败:返回-1

int fgetc(FILE * stream);
功能:从stream指定的文件中读取一个字符
参数:
	stream:文件指针
返回值:
	成功:返回读取到的字符
	失败:-1

int feof(FILE * stream);
功能:检测是否读取到了文件结尾
参数:
	stream:文件指针
返回值:
	非0值:已经到文件结尾
	0:没有到文件结尾

void test(){

	//写文件
	FILE* fp_write= NULL;
	//写方式打开文件
	fp_write = fopen("./mydata.txt", "w+");
	if (fp_write == NULL){
		return;
	}

	char buf[] = "this is a test for pfutc!";
	for (int i = 0; i < strlen(buf);i++){
		fputc(buf[i], fp_write);
	}
	
	fclose(fp_write);

	//读文件
	FILE* fp_read = NULL;
	fp_read = fopen("./mydata.txt", "r");
	if (fp_read == NULL){
		return;
	}

#if 0
	//判断文件结尾 注意:多输出一个空格
	while (!feof(fp_read)){
		printf("%c",fgetc(fp_read));
	}
#else
	char ch;
	while ((ch = fgetc(fp_read)) != EOF){
		printf("%c", ch);
	}
#endif
}

在这里插入图片描述

行读写函数回顾
int fputs(const char * str, FILE * stream);
功能:将str所指定的字符串写入到stream指定的文件中, 字符串结束符 '\0'  不写入文件。 
参数:
	str:字符串
	stream:文件指针
返回值:
	成功:0
	失败:-1

char * fgets(char * str, int size, FILE * stream);
功能:从stream指定的文件内读入字符,保存到str所指定的内存空间,直到出现换行字符、读到文件结尾或是已读了size - 1个字符为止,最后会自动加上字符 '\0' 作为字符串结束。
参数:
	str:字符串
	size:指定最大读取字符串的长度(size - 1)
	stream:文件指针
返回值:
	成功:成功读取的字符串
	读到文件尾或出错: NULL

void test(){

	//写文件
	FILE* fp_write= NULL;
	//写方式打开文件
	fp_write = fopen("./mydata.txt", "w+");
	if (fp_write == NULL){
		perror("fopen:");
		return;
	}

	char* buf[] = {
		"01 this is a test for pfutc!\n",
		"02 this is a test for pfutc!\n",
		"03 this is a test for pfutc!\n",
		"04 this is a test for pfutc!\n",
	};
	for (int i = 0; i < 4; i ++){
		fputs(buf[i], fp_write);
	}
	
	fclose(fp_write);

	//读文件
	FILE* fp_read = NULL;
	fp_read = fopen("./mydata.txt", "r");
	if (fp_read == NULL){
		perror("fopen:");
		return;
	}

	//判断文件结尾
	while (!feof(fp_read)){
		char temp[1024] = { 0 };
		fgets(temp, 1024, fp_read);
		printf("%s",temp);
	}

	fclose(fp_read);
}

块读写函数回顾
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:以数据块的方式给文件写入内容
参数:
	ptr:准备写入文件数据的地址
	size: size_t 为 unsigned int类型,此参数指定写入文件内容的块数据大小
	nmemb:写入文件的块数,写入文件数据总大小为:size * nmemb
	stream:已经打开的文件指针
返回值:
	成功:实际成功写入文件数据的块数,此值和nmemb相等
	失败:0

size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
功能:以数据块的方式从文件中读取内容
参数:
	ptr:存放读取出来数据的内存空间
	size: size_t 为 unsigned int类型,此参数指定读取文件内容的块数据大小
	nmemb:读取文件的块数,读取文件数据总大小为:size * nmemb
	stream:已经打开的文件指针
返回值:
	成功:实际成功读取到内容的块数,如果此值比nmemb小,但大于0,说明读到文件的结尾。
	失败:0

typedef struct _TEACHER{
	char name[64];
	int age;
}Teacher;

void test(){

	//写文件
	FILE* fp_write= NULL;
	//写方式打开文件
	fp_write = fopen("./mydata.txt", "wb");
	if (fp_write == NULL){
		perror("fopen:");
		return;
	}

	Teacher teachers[4] = {
		{ "Obama", 33 },
		{ "John", 28 },
		{ "Edward", 45},
		{ "Smith", 35}
	};
	
	for (int i = 0; i < 4; i ++){
		fwrite(&teachers[i],sizeof(Teacher),1, fp_write);
	}
	//关闭文件
	fclose(fp_write);

	//读文件
	FILE* fp_read = NULL;
	fp_read = fopen("./mydata.txt", "rb");
	if (fp_read == NULL){
		perror("fopen:");
		return;
	}

	Teacher temps[4];
	fread(&temps, sizeof(Teacher), 4, fp_read);
	for (int i = 0; i < 4;i++){
		printf("Name:%s Age:%d\n",temps[i].name,temps[i].age);
	}

	fclose(fp_read);
}

格式化读写函数回顾
int fprintf(FILE * stream, const char * format, ...);
功能:根据参数format字符串来转换并格式化数据,然后将结果输出到stream指定的文件中,指定出现字符串结束符 '\0'  为止。
参数:
	stream:已经打开的文件
	format:字符串格式,用法和printf()一样
返回值:
	成功:实际写入文件的字符个数
	失败:-1

int fscanf(FILE * stream, const char * format, ...);
功能:从stream指定的文件读取字符串,并根据参数format字符串来转换并格式化数据。
参数:
	stream:已经打开的文件
	format:字符串格式,用法和scanf()一样
返回值:
	成功:实际从文件中读取的字符个数
	失败: - 1

注意:fscanf遇到空格和换行时结束。

void test(){

	//写文件
	FILE* fp_write= NULL;
	//写方式打开文件
	fp_write = fopen("./mydata.txt", "w");
	if (fp_write == NULL){
		perror("fopen:");
		return;
	}

	fprintf(fp_write,"hello world:%d!",10);

	//关闭文件
	fclose(fp_write);

	//读文件
	FILE* fp_read = NULL;
	fp_read = fopen("./mydata.txt", "rb");
	if (fp_read == NULL){
		perror("fopen:");
		return;
	}
	
	char temps[1024] = { 0 };
	while (!feof(fp_read)){
		fscanf(fp_read, "%s", temps);
		printf("%s", temps);
	}

	fclose(fp_read);
}

随机读写函数回顾
int fseek(FILE *stream, long offset, int whence);
功能:移动文件流(文件光标)的读写位置。
参数:
	stream:已经打开的文件指针
	offset:根据whence来移动的位移数(偏移量),可以是正数,也可以负数,如果正数,则相对于whence往右移动,如果是负数,则相对于whence往左移动。如果向前移动的字节数超过了文件开头则出错返回,如果向后移动的字节数超过了 文件末尾,再次写入时将增大文件尺寸。
	whence:其取值如下:
		SEEK_SET:从文件开头移动offset个字节
		SEEK_CUR:从当前位置移动offset个字节
		SEEK_END:从文件末尾移动offset个字节
返回值:
	成功:0
	失败:-1

long ftell(FILE *stream);
功能:获取文件流(文件光标)的读写位置。
参数:
	stream:已经打开的文件指针
返回值:
	成功:当前文件流(文件光标)的读写位置
	失败:-1

void rewind(FILE *stream);
功能:把文件流(文件光标)的读写位置移动到文件开头。
参数:
	stream:已经打开的文件指针
返回值:
	无返回值

typedef struct _TEACHER{
	char name[64];
	int age;
}Teacher;

void test(){
	//写文件
	FILE* fp_write = NULL;
	//写方式打开文件
	fp_write = fopen("./mydata.txt", "wb");
	if (fp_write == NULL){
		perror("fopen:");
		return;
	}

	Teacher teachers[4] = {
		{ "Obama", 33 },
		{ "John", 28 },
		{ "Edward", 45 },
		{ "Smith", 35 }
	};

	for (int i = 0; i < 4; i++){
		fwrite(&teachers[i], sizeof(Teacher), 1, fp_write);
	}
	//关闭文件
	fclose(fp_write);

	//读文件
	FILE* fp_read = NULL;
	fp_read = fopen("./mydata.txt", "rb");
	if (fp_read == NULL){
		perror("fopen:");
		return;
	}

	Teacher temp;
	//读取第三个数组
	fseek(fp_read , sizeof(Teacher) * 2 , SEEK_SET);
	fread(&temp, sizeof(Teacher), 1, fp_read);
	printf("Name:%s Age:%d\n",temp.name,temp.age);

	memset(&temp,0,sizeof(Teacher));

	fseek(fp_read, -(int)sizeof(Teacher), SEEK_END);
	fread(&temp, sizeof(Teacher), 1, fp_read);
	printf("Name:%s Age:%d\n", temp.name, temp.age);

	rewind(fp_read);
	fread(&temp, sizeof(Teacher), 1, fp_read);
	printf("Name:%s Age:%d\n", temp.name, temp.age);

	fclose(fp_read);
}

三、文件读写案例

1.读写配置文件

在这里插入图片描述

struct ConfigInfo
{
	char key[64];
	char value[64];
};

//获取文件有效行数
int getFileLine(const char  * filePath)
{
	FILE * file = fopen(filePath, "r");
	char buf[1024] = {0};
	int lines = 0;
	while (fgets(buf,1024,file) != NULL)
	{
		if (isValidLine(buf))
		{
			lines++;
		}
		memset(buf, 0, 1024);
	}
	 
	fclose(file);
	
	return lines;

}
//解析文件
void parseFile(const char  * filePath, int lines, struct ConfigInfo** configInfo)
{

	struct ConfigInfo * pConfig =  malloc(sizeof(struct ConfigInfo) * lines);

	if (pConfig == NULL)
	{
		return;
	}



	FILE * file = fopen(filePath, "r");
	char buf[1024] = { 0 };
	
	int index = 0;
	while (fgets(buf, 1024, file) != NULL)
	{
		if (isValidLine(buf))
		{
			//解析数据到struct ConfigInfo中
			memset(pConfig[index].key, 0, 64);
			memset(pConfig[index].value, 0, 64);
			char * pos = strchr(buf, ':');
			strncpy(pConfig[index].key, buf, pos - buf);
			strncpy(pConfig[index].value, pos + 1, strlen(pos + 1) - 1); // 从第二个单词开始截取字符串,并且不截取换行符
			//printf("key = %s\n", pConfig[index].key);
			//printf("value = %s\n", pConfig[index].value);
			index++;
		}
		memset(buf, 0, 1024);
	}



	*configInfo = pConfig;

}

//获取指定的配置信息
char * getInfoByKey(char * key, struct ConfigInfo*configInfo ,int lines)
{
	for (int i = 0; i < lines;i++)
	{
		if (strcmp(key, configInfo[i].key) == 0)
		{
			return configInfo[i].value;
		}
	}
	return NULL;
}

//释放配置文件信息
void freeConfigInfo(struct ConfigInfo*configInfo)
{
	free(configInfo);
	configInfo = NULL;
}

//判断当前行是否为有效行
int isValidLine(char * buf)
{
	if (buf[0] == '0' || buf[0] == '\0' || strchr(buf,':') == NULL)
	{
		return 0;// 如果行无限 返回假
	}
	return 1;
}

int main(){

	char * filePath = "./config.txt";
	int lines = getFileLine(filePath);
	printf("文件有效行数为:%d\n", lines);

	struct ConfigInfo * config = NULL;
	parseFile(filePath, lines, &config);

	printf("heroId = %s\n", getInfoByKey("heroId", config, lines));
	printf("heroName: = %s\n", getInfoByKey("heroName", config, lines));
	printf("heroAtk = %s\n", getInfoByKey("heroAtk", config, lines));
	printf("heroDef: = %s\n", getInfoByKey("heroDef", config, lines));
	printf("heroInfo: = %s\n", getInfoByKey("heroInfo", config, lines));


	freeConfigInfo(config);
	config = NULL;

	system("pause");
	return EXIT_SUCCESS;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值