首页 > 其他分享 >【C语言】文件操作强化

【C语言】文件操作强化

时间:2024-06-05 16:29:54浏览次数:18  
标签:文件 stream int C语言 char read FILE 强化

【C语言】文件操作强化


文章目录


前言

本篇文章我们将详细讲到文件操作的相关函数使用和文件加密和解密的相关内容。


一、文件打开关闭

文件打开(fopen)

文件的打开操作表示将给用户指定的文件在内存分配一个FILE结构区,并将该结构的指针返回给用户程序,以后用户程序就可用此FILE指针来实现对指定文件的存取操作了。当使用打开函数时,必须给出文件名、文件操作方式(读、写或读写)。

FILE * fopen(const char * filename, const char * mode);
功能:打开文件
参数:
filename:需要打开的文件名,根据需要加上路径
mode:打开文件的权限设置
返回值:
成功:文件指针
失败:NULL
在这里插入图片描述

void test(){
	
	FILE *fp = NULL;

	// "\\"这样的路径形式,只能在windows使用
	// "/"这样的路径形式,windows和linux平台下都可用,建议使用这种
	// 路径可以是相对路径,也可是绝对路径
	fp = fopen("../test", "w");
	//fp = fopen("..\\test", "w");

	if (fp == NULL) //返回空,说明打开失败
	{
		//perror()是标准出错打印函数,能打印调用库函数出错原因
		perror("open");
		return -1;
	}
}
//应该检查fopen的返回值!如何函数失败,它会返回一个NULL值。如果程序不检查错误,这个NULL指针就会传给后续的I/O函数。它们将对这个指针执行间接访问,并将失败.


文件关闭(fclose)

文件操作完成后,如果程序没有结束,必须要用fclose()函数进行关闭,这是因为对打开的文件进行写入时,若文件缓冲区的空间未被写入的内容填满,这些内容不会写到打开的文件中。只有对打开的文件进行关闭操作时,停留在文件缓冲区的内容才能写到该文件中去,从而使文件完整。再者一旦关闭了文件,该文件对应的FILE结构将被释放,从而使关闭的文件得到保护,因为这时对该文件的存取操作将不会进行。文件的关闭也意味着释放了该文件的缓冲区。

int fclose(FILE * stream);
功能:关闭先前fopen()打开的文件。此动作让缓冲区的数据写入文件中,并释放系统所提供的文件资源。
参数:
stream:文件指针
返回值:
成功:0
失败:-1

它表示该函数将关闭FILE指针对应的文件,并返回一个整数值。若成功地关闭了文件,则返回一个0值,否则返回一个非0值.


二、文件读写函数

  • 按照字符读写文件:fgetc(), fputc()
  • 按照行读写文件:fputs(), fgets()
  • 按照块读写文件:fread(), fwirte()
  • 按照格式化读写文件:fprintf(), fscanf()
  • 按照随机位置读写文件:fseek(), ftell(), rewind()

字符读写函数

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:没有到文件结尾

//按照字符读写文件:fgetc(), fputc()
void test01()
{
	//写文件

	FILE* f_write = fopen("./test01.txt", "w+");

	if (f_write == NULL)
	{
		return;
	}

	char buf[] = "This is the first test";
	for (int i = 0; i < strlen(buf); i++)
	{
		fputc(buf[i], f_write);
	}
	fclose(f_write);


	//读文件

	FILE* f_read = fopen("./test01.txt", "r");	
	if (f_read == NULL)
	{
		return;
	}
	char ch;
	while ((ch = fgetc(f_read)) != EOF)	// EOF  Enf of File
	{
		printf("%c", ch);
	}
	fclose(f_read);
}

行读写函数

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

//按照行读写文件:fputs(), fgets()
void test02()
{
	//写文件
	FILE* f_write = fopen("./test02.txt", "w");
	if (f_write == NULL)
	{
		return;
	}
	char* buf[] =
	{
		"锄禾日当午\n",
		"汗滴禾下土\n",
		"谁知盘中餐\n",
		"粒粒皆辛苦\n",
	};
	for (int i = 0; i < 4; i++)
	{
		fputs(buf[i], f_write);
	}
	fclose(f_write);

	//读文件
	FILE* f_read = fopen("./test02.txt", "r");
	if (f_read == NULL)
	{
		return;
	}
	while (!feof(f_read))
	{
		char buf[1024] = { 0 };
		fgets(buf, 1024, f_read);
		printf("%s", buf);
	}
	fclose(f_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

//按照块读写文件:fread(),fwrite()
struct Hero
{
	char name[64];
	int age;
};
void test03()
{
	//写文件 wb二进制方式
	FILE* f_write = fopen("./test03.txt", "wb");
	if (f_write == NULL) 
	{
		return;
	}

	struct Hero heros[4] =
	{
		{ "亚瑟" , 18 },
		{ "赵云", 28 },
		{ "妲己", 19 },
		{ "孙悟空", 99 },
	};
	for (int i = 0; i < 4; i++)
	{
		//参数1 数据地址  参数2  块大小   参数3  块个数   参数4  文件指针
		fwrite(&heros[i], sizeof(struct Hero), 1, f_write);
	}
	fclose(f_write);

	//读文件
	FILE* f_read = fopen("./test03.txt", "rb");// read binary
	if (f_read == NULL) 
	{ 
		return;
	} 
	struct Hero temp[4];
	//参数1 数据地址  参数2  块大小   参数3  块个数   参数4  文件指针
	fread(&temp, sizeof(struct Hero), 4, f_read);

	for (int i = 0; i < 4; i++)
	{
		printf("姓名:%s 年龄:%d \n", temp[i].name, temp[i].age);
	}
	fclose(f_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遇到空格和换行时结束。

//按照格式化读写文件:fprintf(), fscanf()
void test04()
{
	//写文件
	FILE* f_write = fopen("./test04.txt", "w");
	if (f_write == NULL)
	{
		return;
	}
	fprintf(f_write, "hello world %d年 %d月 %d日", 2024, 5, 30);
	//关闭文件
	fclose(f_write);

	//读文件
	FILE* f_read = fopen("./test04.txt", "r");
	if (f_read == NULL)
	{
		return;
	}
	char buf[1024] = { 0 };
	while(!feof(f_read)) 
	{
		fscanf(f_read, "%s", buf);
		printf("%s", buf);
	}
	fclose(f_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:已经打开的文件指针
返回值:
无返回值

//按照随机位置读写文件
void test05()
{
	FILE* f_write = fopen("./test05.txt", "wb");
	if (f_write == NULL) 
	{
		return;
	}
	struct Hero heros[4] = 
	{
		{ "亚瑟", 18 },
		{ "赵云", 28 },
		{ "妲己", 19 },
		{ "孙悟空", 99 },
	};
	for (int i = 0; i < 4; i++)
	{
		//参数1 数据地址  参数2  块大小   参数3  块个数   参数4  文件指针
		fwrite(&heros[i], sizeof(struct Hero), 1, f_write); 
	}
	fclose(f_write); 

	//读取妲己数据
	FILE* f_read = fopen("./test05.txt", "rb"); 
	if (f_read == NULL) 
	{
		//error 宏 

		//printf("文件打开失败\n");
		perror("文件打开失败"); 
		return;
	}
	//创建临时结构体
	struct Hero temp; 

	//改变文件光标位置
	fseek(f_read, sizeof(struct Hero) * 2, SEEK_SET);

	fseek(f_read, -(long)sizeof(struct Hero) * 2, SEEK_END);

	rewind(f_read); //将文件光标置首

	fread(&temp, sizeof(struct Hero), 1, f_read);

	printf("姓名: %s 年龄: %d\n", temp.name, temp.age);

	fclose(f_read); 
}

三、文件读写注意事项

//注意事项1
void test01()
{
	FILE* f_read = fopen("./test.txt", "r");
	if (f_read == NULL)
	{
		return;
	}

	char ch;

#if 0
	//aaaaaaaaaEOF
	//         |
	while (!feof(f_read))
	{
		ch = fgetc(f_read);

		if (feof(f_read))
		{
			break;
		}

		printf("%c", ch);
	}
#endif 

	while ((ch = fgetc(f_read)) != EOF)
	{
		printf("%c", ch);
	}

	fclose(f_read);
}

//注意事项2 
struct Hero
{
	char* name; //如果属性开辟到堆区,不要存指针到文件中,要将指针指向的内容存放到文件中
	int age;
};




int main() {
	test01();
	//printf(" aaaaa\n");
	//printf("%caaaaa\n",EOF);
	system("pause");
	return EXIT_SUCCESS;
}

四、配置文件读写案例

  • 1.文件中按照键值对方式 存放了有效的信息需要解析出来
    2.创建 config.h 和 config.c做配置文件读操作
    3.获取有效信息的行数 getFileLines
    4.判断字符串是否是有效行 int isValidLines(char *str)
    5.解析文件到配置信息数组中 void parseFile(char * filePath, int lines , struct ConfigInfo ** configinfo);
    6通过key获取value值 char * getInfoByKey(char * key, struct ConfigInfo * configinfo, int len);
    7释放内存 void freeConfigInfo(struct ConfigInfo * configinfo);
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include "config.h"


int main(){

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

	struct ConfigInfo * configInfo = NULL;
	parseFile(filePath, len, &configInfo);

	//测试根据key获取value
	printf("heroId = %s\n", getInfoByKey("heroId", configInfo, len));
	printf("heroName = %s\n", getInfoByKey("heroName", configInfo, len));
	printf("heroAtk = %s\n", getInfoByKey("heroAtk", configInfo, len));
	printf("heroDef = %s\n", getInfoByKey("heroDef", configInfo, len));
	printf("heroInfo = %s\n", getInfoByKey("heroInfo", configInfo, len));

	//释放空间
	freeConfigInfo(configInfo);
	configInfo = NULL;


	system("pause");
	return EXIT_SUCCESS;
}

config.c

#include "config.h"

int getFileLines(char * filePath)
{
	FILE * file = fopen(filePath, "r");
	if (file == NULL)
	{
		return -1;
	}

	char buf[1024] = { 0 };
	int lines = 0;
	while ( fgets(buf,1024,file) != NULL)
	{
		if (isValidLines(buf))
		{
			lines++;
		}
		memset(buf, 0, 1024);
	}

	return lines;

	fclose(file);
}

int isValidLines(char *str)
{
	if (strchr(str, ':') == NULL)
	{
		return 0; //返回假 代表无效行
	}

	return 1;
}

//解析文件
void parseFile(char * filePath, int lines, struct  ConfigInfo ** configinfo)
{
	struct ConfigInfo * info = malloc(sizeof(struct ConfigInfo) * lines);

	if (info == NULL)
	{
		return;
	}

	FILE * file = fopen(filePath, "r");
	if (file == NULL)
	{
		return;
	}
	char buf[1024] = { 0 };
	int index = 0;
	while ( fgets(buf,1024,file ) != NULL)
	{
		if (isValidLines(buf))
		{
			//有效信息 才去解析
			//清空 key和value数组
			//heroName:aaaa\n
			memset(info[index].key, 0, 64);
			memset(info[index].value, 0, 64);
			char * pos = strchr(buf, ':');
			strncpy(info[index].key, buf, pos - buf);
			strncpy(info[index].value, pos + 1, strlen(pos + 1)-1);
			index++;
		}
		memset(buf, 0, 1024);
	}
	*configinfo = info;
}

char * getInfoByKey(char * key, struct ConfigInfo * configinfo, int len)
{
	for (int i = 0; i < len;i++)
	{
		if (strcmp(key, configinfo[i].key) == 0)
		{
			return configinfo[i].value;
		}
	}

	return NULL;
}

//释放内存
void freeConfigInfo(struct ConfigInfo * configinfo)
{
	if (configinfo != NULL)
	{
		free(configinfo);
		configinfo = NULL;
	}
}

config.h

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//配置信息 结构体
struct ConfigInfo
{
	char key[64];
	char value[64];
};

//获取有效行数
int getFileLines(char* filePath);

//检测当前行是否是有效信息
int isValidLines(char* str);

//解析文件
void parseFile(char* filePath, int lines, struct  ConfigInfo** configinfo);

//根据key获取对应value
char* getInfoByKey(char* key, struct ConfigInfo* configinfo, int len);

//释放内存
void freeConfigInfo(struct ConfigInfo* configinfo);

总结

到这里这篇文章的内容就结束了,谢谢大家的观看,如果有好的建议可以留言喔,谢谢大家啦!

标签:文件,stream,int,C语言,char,read,FILE,强化
From: https://blog.csdn.net/2301_80035097/article/details/138963770

相关文章

  • MySql数据库ibtmp1文件增长问题处理记录
    背景:正式环境磁盘满了,排查后发现是mysql中data目录下的ibtmp1文件增长超过1TB,网上查,发现ibtmp1文件是InnoDB存储引擎的临时表空间文件。用于存储临时表、排序等操作的临时数据文件。解决方法:1.重启mysql实例释放ibtmp1文件;2.限制ibtmp1文件大小:innodb_temp_data_file_path=ibt......
  • sqlserver 通过压缩bak文件实现从服务器还原数据库《数据差异数个小时》
    十年河东,十年河西,莫欺少年穷学无止境,精益求精1、备份主服务器数据库并压缩publicvoidDbBack(){varbakname=@"ChargeDB_"+DateTime.Now.ToString("yyyyMMdd")+".bak";stringfilepath=@"D:\dbback\"+bakna......
  • 视频文件批量更换名称的方法有哪些?分享4个高效的方法
    我们有一大批视频文件需要重新命名时,手动一个一个地操作显然非常低效。为了解决这个问题,我们可以借助一些工具来实现批量重命名操作。下面分享4个高效的方法,帮助你快速完成大量视频文件的重命名方法一:使用【汇帮批量重命名】以下是具体的操作步骤:1:下载并安装“汇帮批量重命......
  • 怎么给文件夹按号码命名?文件夹批量重命名的4个方法
    在我们工作中会积累很多文件夹,或者存储一类信息时也会产生很多文件夹,有时候我们需要把这些文件夹的名称进行编号。因为通过使用数字序号可以准确地描述文件夹的优先级,方便排序和快速定位。可以统一文件夹命名的格式,提高文件管理的效率。而对于文件名和文件UUID有规律的文件,使用......
  • pdf文件可以转成html网页吗?
    目前我们工作或学习中使用最多的可能就是PDF格式的文档了,它虽然有很多好处,但是有时如果文档比较大,传送就比较麻烦,这时我们将其转换成HTML再发送就很方便了。那么pdf格式怎么转html格式呢?方法一、使用在线pdf转html如果不想下载软件的话,一些在线工具例如smallpdf中文版、speedpdf......
  • C语言判断文件存在和创建文件
    用C语言可以实现新建文件,这里要用到一个fopen函数,它是一个非常强大的函数,可以以各种方式创建、读取文件,具体语法如下:文件指针名=fopen(文件名,使用文件方式);“文件指针名”必须是被说明为File类型的指针变量;“文件名”是被打开文件的文件名,也包括路径;“使用文件方式”是指文件的......
  • 企业文件加密:数据保护的实战策略
    数据是企业的生命线,保护数据安全就是保护企业的竞争力。在众多数据保护措施中,文件加密因其直接有效而备受青睐。一、为何文件加密至关重要在数字化办公时代,企业机密和敏感数据的泄露可能带来毁灭性的后果。文件加密能够确保即使数据被盗,也无法被未授权者访问或解读。二、文件......
  • andorid属性读写 + 恢复出厂设置保存文件标志位到 persist 分区
    1.关于selinux权限和用户权限组修改device/feixiang/sepolicy/radio.te allowradiopersist_file:dir{searchgetattrreadwriteadd_nameremove_name}; allowradiopersist_file:file{getattrreadwritecreateopenunlink}; system/core/rootdir......
  • Python结合文件名称将多个文件复制到不同路径下
      本文介绍基于Python语言,针对一个文件夹下的大量栅格遥感影像文件,基于其各自的文件名,分别创建指定名称的新文件夹,并将对应的栅格遥感影像文件复制到不同的新文件夹下的方法。  首先,我们来看一下本文需要实现的需求。现有一个文件夹,其中有大量.tif格式的栅格遥感影像文件,以及......
  • hdfs小文件是啥意思
    所谓小文件,即存储在hdfs上的数据文件明显小于hdfs文件块大小的(默认是64MB)。小文件过多,占用大量内存。小文件的产生:主要由Hive启动的mr任务生成。在hdfs中,每次读写文件都需要先从namenode获取表结构(元数据),然后再与datanode建立连接。而访问大量的小文件会经常需要大量的定位......