文件操作详解:fgetc,fputc,fgets,fputs,fscanf,,fprintf,fread,fwrite的使用和例子 C语言

前言

        在日常应用中,我们为了持续的使用一些数据,为了让数据可以在程序退出后可以保存并正常使用,引入了文件的概念和操作。本文分享了一些常用的文件操作函数的使用方法和各自的区别。

一、常用文件顺序读写函数

下面例程所使用的VS工程代码见:👇

fgetc fputc fgets fputs fscanf fprintf fread fwrite文件操作函数使用例程代码

常用的文件操作函数
功能函数名用于

字符输入函数

fgetc

所有输入流

字符输出函数

fputc

所有输出流

文本行输入函数

fgets

所有输入流

文本行输出函数

fputs

所有输出流

格式化输入函数

fscanf

所有输入流

格式化输出函数

fprintf

所有输出流

二进制输入

fread

文件

二进制输出

fwrite

文件

二、字符操作函数 fgetc 和 fputc

fgetc

c在这里指的是char

官方解释如上图

  • 从流中获取字符
  • 返回指定流的内部文件位置指示符当前指向的字符。然后将内部文件位置指示符推进到下一个字符
  • 如果流在被调用时位于文件的末尾,则该函数返回 EOF 并为流设置文件结束指示器(feof)
  • 如果发生读错误,该函数返回EOF并设置流的错误指示器(error)
  • Fgetc  getc 是等价的,除了 getc 可以在某些库中作为宏实现

为此我们写了个文件

在确保了文件可以有内容读取后,我们编程实现观察结果,我们以读取的方式打开文件,然后使用 ch 变量挨个读取文件中的字符并且打印。

int char_operation1(void)
{
	FILE* pf = fopen("data1.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//读文件
	int ch = fgetc(pf);
	printf("%c", ch);
	ch = fgetc(pf);
	printf("%c", ch);
	ch = fgetc(pf);
	printf("%c", ch);
	ch = fgetc(pf);
	printf("%c", ch);
	ch = fgetc(pf);
	printf("%c", ch);

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
	
}

调用此函数并获取结果如下

  • 综上:fgetc 函数可以挨个读取文件中的字符,我们可以定义一个变量来接收 fgets 的返回值(字符的ASCII码)然后进行输出等操作

  • 在使用该函数的时候,我们只需要将文件指针(流)作为参数传给函数,然后我们就可以得到一个字符的ASCII码

fputc

官方解释如上图

  • 将字符写入流
  • 将一个字符写入流并推进位置指示器
  • 字符被写入流的内部位置指示器所指示的位置,然后自动向前移动一个

在实验前创建一个空白的文件

int char_operation2(void)
{
	//打开文件
	FILE* pf = fopen("data2.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//写文件
	fputc('a', pf);
	fputc('b', pf);
	fputc('c', pf);
	fputc('d', pf);
	fputc('e', pf);

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

运行后:

通过 fputc 函数挨个对文件输入了从 ‘a’ 到 ‘e’ 的字符 

综合上述操作,我们可以得出结论,fputc 函数可以挨个字符的对文件进行写入的操作,函数内部需要注意的有俩个参数

  1. 要写入的字符
  2. 要写入文件的文件指针(流)

三、文本行操作函数fgets 和 fputs

fgets

s指的是string

  • 从流中获取字符串
  • 从流中读取字符,并将其作为C字符串存储到 str 中,直到读取 (num-1) 个字符,或者到达换行符或文件结束符,以先发生的为准
  • 换行符使 fgets 停止读取,但它被函数认为是一个有效字符,并包含在复制到 str 的字符串中。
  • 在复制到 str 的字符之后,将自动追加一个终止 null 字符。
  • 请注意,fgets  gets 有很大的不同:fgets 不仅接受流参数,而且允许指定 str 的最大长度,并在字符串中包含任何结束换行符。

提前准备一个txt文件

int string_operation1(void)
{
	//打开文件
	FILE* pf = fopen("data3.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//读文件
	char arr[100] = { 0 };
	fgets(arr, 100, pf);
	printf("%s", arr);

	fgets(arr, 100, pf);
	printf("%s", arr);

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

运行结果如下:

根据输出结果,我们可以发现,一条 fgets 函数可以读取一行的内容,但是在使用的时候需要注意设置一个字符数组来接收字符串,函数在使用时,一共有三个参数

  1. 要传入数组的地址
  2. 要复制到字符串中的最大字符数
  3. 文件指针(流)

fputs

  • 将字符串写入流
  • 将由 str 指向的C字符串写入流
  • 函数从指定的地址 (str) 开始复制,直到到达结束的空字符 ('\0'),这个终止的空字符不会复制到流中
  • 注意,fputs 与 puts 的不同之处不仅在于可以指定目标流,而且 fputs 不会写入额外的字符,而 puts 会自动在末尾附加一个换行符
int string_operation2(void)
{

	//打开文件
	FILE* pf = fopen("data4.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//写文件
	char arr[] = "hello world\n";
	fputs(arr, pf);

	fputs("Deadly Bug", pf);

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

首先还是设定一个空白内容的 data.txt 的文件

运行结果如下

根据运行结果,我们可以判断, fputs 函数一次性可以对文件写入一行字符串,只要声明字符串的内容或者地址,都可以进行写入,它的俩个参数分别如下:

  1. 要写入的字符串的内容或者地址
  2. 要写入的文件指针(流) 

四、格式化文件操作函数fscanf 和 fprintf

fscanf

  • 从流中读取格式化的数据
  • 从流中读取数据,并根据参数格式将其存储到附加参数所指向的位置
  • 额外的参数应该指向已经分配的对象,其类型由格式字符串中相应的格式说明符指定

需要以特定的格式的字符串

int format_operation1(void)
{

	struct S s = { 0 };

	//打开文件
	FILE* pf = fopen("data5.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//读文件
	fscanf(pf, "%f %c %d", &(s.f), &(s.c), &(s.n));
	printf("%f %c %d\n", s.f, s.c, s.n);

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

注:格式应与文件中一样

根据输出结果,我们可以发现,原本文件中的字符串,被我们以 float char int 的格式分别读到了 f,c,n 三个变量中,也就是说我们将原本的字符串变成了不同格式的数据,在使用这个函数时,注意他的参数,只比 scanf 多了一个参数,也就是文件指针(流)

fprintf

  • 将格式化的数据写入流
  • 将由 format 指向的 C字符串写入流。如果 format 包含格式说明符(以%开头的子序列),则格式化format 之后的其他参数并将其插入到结果字符串中,以替换它们各自的说明符。
  • 在format 形参之后,函数期望至少与format 指定的一样多的附加参数。
int format_operation2(void)
{

	struct S s = { 1.2345f, 'a', 100 };

	//打开文件
	FILE* pf = fopen("data6.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//写文件
	fprintf(pf, "%f-%c-%d", s.f, s.c, s.n);

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;

}

运行结果如下:

根据输出结果,我们可以发现,我们以结构体的格式,将其中 float char int 三种类型的数据写入了文件,在写入文件后,这些数据就失去了原本的格式,相当于变成了一条字符串,在使用的时候,他只比我们的 scanf 多了一个参数,也就是文件指针(流) 

五、二进制文件操作函数

fread

  • 从流中读取数据块
  • 从流中读取一个由 count 元素组成的数组,每个元素的大小为 size 字节,并将它们存储在 ptr 指定的内存块中
  • 流的位置指示器按读取的总字节数前进
  • 如果成功读取的总字节数为 (size*count)

参数

  • void * ptr:指向大小至少为(size*count)字节的内存块的指针,转换为 void* 
  • size_t size:要读取的每个元素的大小(以字节为单位)
  • size_t count:元素的数目,每个元素的大小为 size 字节
  • FILE * stream:指向指定输入流的 FILE 对象的指针(文件指针)

首先有个txt文件

int binary_operation1()
{
	//二进制的方式读取文件

		int arr[15] = { 0 };

		//写文件
		FILE* pf = fopen("data7.txt", "rb");
		if (pf == NULL)
		{
			perror("fopen");
			return 1;
		}

		//二进制的读文件
		fread(arr, sizeof(arr[0]), sizeof(arr) / sizeof(arr[0]), pf);

		int i = 0;
		for (i = 0; i < 15; i++)
		{
			printf("%d ", arr[i]);//以二进制文件读取的所以是乱数
		}

		//关闭文件
		fclose(pf);
		pf = NULL;

		return 0;


}

运行结果如下

 结果和预期的完全不一样,这是因为是以二进制的方式读取,打印的时候却是以十进制的方式打印,这样就相当于给数据加密了,我们无法直观的看见我们读取了什么数据,但是我们确确实实是读取到了。那么如何读取到呢?下面会做出介绍

fwrite

  • 将数据块写入流
  • 将由 count 元素组成的数组 (每个元素的大小为 size 字节) 从 ptr 所指向的内存块写入流中的当前位置
  • 流的位置指示器按写入的总字节数前进
  • 在内部,该函数将 ptr 指向的块解释为 unsigned char 类型的 (size*count) 元素数组,并将它们顺序写入流,就像对每个字节调用 fputc 一样

参数:

  • void * ptr:指向大小至少为(size*count)字节的内存块的指针,转换为 void* 
  • size_t size:要写入的每个元素的大小(以字节为单位)
  • size_t count:元素的数目,每个元素的大小为 size 字节
  • FILE * stream:指向指定输入流的 FILE 对象的指针(文件指针)
int binary_operation2()
{
	//二进制的方式写进文件

	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };

	//写文件
	FILE* pf = fopen("data8.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//二进制的写文件
	fwrite(arr, sizeof(arr[0]), sizeof(arr) / sizeof(arr[0]), pf);

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;

}

运行结果如下:

同样,我们还是无法直观的看见我们存储了什么,这是因为记事本使用的是 UTF-8 码,和我们保存的二进制并不兼容,这从十进制转到二进制再用 UTF-8 码进行显示也就相当于对文本进行了一层加密,解铃还须系铃人,通过fread读取试一下

int binary_operation3()
{
	//二进制的方式读取文件

	int arr[10] = { 0 };

	//写文件
	FILE* pf = fopen("data8.txt", "rb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//二进制的读文件
	fread(arr, sizeof(arr[0]), sizeof(arr) / sizeof(arr[0]), pf);

	int i = 0;
	for (i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;

}

运行结果如下

这一次可以正确读取到数据了,也就是说fread 和 fwrite都不会影响数据的真实性,只是被加密了,无法直观看到。

总结:

fgetc:从文件中读取单个字符(char)

fputc:对文件写入单个字符(char)

fgets:从文件中读取一个字符串(string)

fputs:对文件写入一个字符串(string)

fscanf:将文件中的字符串转换为有格式的数据并且读取出来(format)

fprintf:将有格式的数据转换为字符串并且写入文件(format)

fread:将文件中的内容转换为二进制然后读取出来(binary)

fwrite:将数据转换为二进制然后写入文件(binary)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值