C语言-常见文件操作函数详解(fgetc,fputc,fgets,fputs,fscanf,fprintf,fread,fwrite)

🌏个人博客:尹蓝锐的博客

希望文章能够给到初学的你一些启发~ 如果觉得文章对你有帮助的话,点赞 + 关注+ 收藏支持一下笔者吧~

顺序读写数据常用函数

|---------|------------------------------|----------------------------------------------------------------------------------------------|-------------------------------|
| 函数名 | 调用形式 | 功能 | 返回值 |
| fgetc | fgetc(fp) | 从指针变量fp指向的文件中读入一个字符 | 读成功,返回所读字符,失败返回EOF(即-1) |
| fputc | fputc(fp) | 把字符ch写到文件指针变量fp所指向的文件中 | 输出成功返回值就是输出的字符,输出失败返回EOF(即-1) |
| fgets | fgets(str,n,fp) | 从fp指向的文件读入一个**长度为(n-1)的字符串,存放到字符数组str中 tips :读n-1个是因为fgets函数要固定留一个字符'\0'**作为字符串结束标志 | 读成功,返回地址str,失败则返回NULL |
| fputs | fputs(str,fp) | 把str所指向的字符串写到文件指针变量fp所指向的文件中 | 输出成功,返回0;否则返回非0值 |
| fscanf | fscanf(fp,"%d",i) | 将int类型变量i的值按照%d的格式输出到fp指向的文件中 | 成功后,将返回写入的字符总数。否则并返回负数。 |
| fprintf | fprintf(fp,"%f",j) | 将float类型的变量j的值按照%f的格式输出到屏幕上 | 成功后,将返回写入的字符总数。否则并返回负数。 |
| fread | fread(buffer,size,count,fp) | 从fp中读取一个含有count个元素的数组,每个元素的大小为size个字节,并将其存储在buffer指定的内存块中。 | 返回成功读取的元素总数 |
| fwrite | fwrite(buffer,size,count,fp) | 从buffer指向的内存块向文件流中写入一个包含count个元素数组,每个元素的大小为size个字节。流的位置指示器按写入的总字节数前进。 | 返回成功写入的元素总数。 |

1、fgetc

int fgetc ( FILE * stream );

  1. 从流中获取字符
  2. 返回指定流的内部文件位置指示符当前指向的字符。然后,内部文件位置指示器将前进到下一个字符。
  3. 如果调用时流位于文件末尾,则函数返回EOF并为流设置文件末尾指示符(feof)。
  4. 如果发生读取错误,该函数将返回EOF并为流设置错误指示符(ferror)。
  5. fgetc和getc是等效的,除了getc可以在某些库中实现为宏。

为了更加具体理解,我们创建一个文件并输入一些字符

在保证文件有内容可读取后,我们以只读 的方式打开文件,使用ch变量挨个读取文件中的字符

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	FILE *fp = fopen("test.txt", "r");
	if (fp == NULL)
	{
		perror("fopen");
		return 1;
	}
	char ch = getc(fp);
	printf("%c", ch);
	ch = getc(fp);
	printf("%c", ch);
	fclose(fp);
	fp = NULL;
	return 0;
}

运行结果如下:

2、fputc

int fputc ( int character, FILE * stream );

  1. 向流写入字符将字符写入流并推进位置指示器。
  2. 字符被写在流的内部位置指示器指示的位置,然后自动前进一个。

使用fputc向文件中挨个写入字符

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	FILE *fp = fopen("test.txt", "w");//只写方式打开
	if (fp == NULL)
	{
		perror("fopen");
		return 1;
	}
	char ch[10] = "excellent!";
	for (int i = 0; i < 10; i++)
	{
		fputc(ch[i], fp);
	}
	fclose(fp);
	fp = NULL;
	return 0;
}

运行结果如下,test被成功写入字符

这里需要注意 的是:如果test.txt文件中本来有内容,原来的内容会被清空

3、fgets

char * fgets ( char * str, int num, FILE * stream );

  1. 从流中获取字符串
  2. 从流中读取字符,并将其作为字符串存储到str中,直到读取了**(num-1)**个字符,或者到达换行符或文件末尾,以先发生者为准。
  3. 换行符会使fgets停止读取,但函数会将其视为有效字符,并将其包含在复制到str的字符串中。
  4. 在复制到str的字符之后,会自动附加一个终止空字符。
  5. 请注意,fgets与gets有很大不同:fgets不仅接受流参数,还允许指定str的最大大小,并在字符串中包含任何换行符。

确保test.txt文件有内容的情况下,用只读方式打开文件

通过fgets函数获取文件中的字符串并将其保存至字符数组ch中,代码如下

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	FILE *fp = fopen("test.txt", "r");//只读方式打开
	if (fp == NULL)
	{
		perror("fopen");
		return 1;
	}
	char ch[10];
	fgets(ch, sizeof(ch), fp);
	puts(ch);
	fclose(fp);
	fp = NULL;
	return 0;
}

运行结果如下

我们需要注意的是本代码调用fgets函数时,第二个参数使用sizeof(ch),计算字符数组ch所占字节数,计算结果值为10,而fgets函数第二个参数代表取10-1个,即9个字符,所以文件中只有9个字符被存入字符数组ch中,原本文件内容excellent后的 !没有被输出

4、fputs

复制代码
int fputs ( const char * str, FILE * stream );
  1. 将字符串写入流
  2. 将str指向的字符串写入流。
  3. 函数从指定的地址(str)开始复制,直到到达终止的空字符("\0")。此终止空字符不会复制到流中。
  4. 请注意,fputs与put的不同之处不仅在于可以指定目标流,而且fputs不会写入额外的字符,而put会自动在末尾添加换行符。

通过fputs函数向文件中写入字符串

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	FILE *fp = fopen("test.txt", "w");//只写方式打开
	if (fp == NULL)
	{
		perror("fopen");
		return 1;
	}
	char ch[11]="wonderful!";
	fputs(ch,fp);

	fclose(fp);
	fp = NULL;
	return 0;
}

运行结果如下:

5、fscanf

复制代码
int fscanf ( FILE * stream, const char * format, ... );
  1. 从流中读取格式化数据
  2. 从流中读取数据,并根据参数格式将其存储到附加参数指向的位置。
  3. 附加参数应指向格式字符串中由其相应格式说明符指定的类型的已分配对象。

首先保证test.txt文件中有内容

使用scanf用格式化的方式读取文件中的内容,代码如下

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	FILE *fp = fopen("test.txt", "r");//只写方式打开
	if (fp == NULL)
	{
		perror("fopen");
		return 1;
	}
	int n;
	fscanf(fp, "%d", &n);
	printf("%d", n);
	fclose(fp);
	fp = NULL;
	return 0;
}

运行结果如下

6、fprintf

复制代码
int fprintf ( FILE \* stream, const char \* format, ... );
  1. 将格式化数据写入流
  2. 将按格式指向的字符串写入流。如果format包含格式说明符(以%开头的子序列),则格式化format之后的其他参数并将其插入到结果字符串中,替换其各自的说明符。
  3. 在format参数之后,函数需要至少与format指定的额外参数一样多的参数。

使用fprintf函数向文件中格式化输出内容

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	FILE *fp = fopen("test.txt", "w");//只写方式打开
	if (fp == NULL)
	{
		perror("fopen");
		return 1;
	}
	int n = 123456;
	fprintf(fp, "%d", n);
	
	fclose(fp);
	fp = NULL;
	return 0;
}

运行结果如下:

7、fread

复制代码
size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
  1. 从流中读取数据块
  2. 从流中读取一个count个元素组成的数组,每个元素的大小为size个字节 ,并将其存储在ptr指定的内存块中。
  3. 流的位置指示器按读取的总字节数前进。
  4. 如果成功,读取的字节总数为(size(大小)*count(计数))。

该函数一共有4个参数:

  1. ptr指向大小至少为(大小*计数)字节的内存块的指针,转换为void*。
  2. size要读取的每个元素的大小(以字节为单位)。
  3. size_t是一个无符号整数类型。
  4. count元素的数量,每个元素的大小为字节。
  5. size_t是一个无符号整数类型。
  6. stream指向指定输入流的FILE对象的指针。

首先保证test.dat该二进制文件中有数据,我这里给的是123456,可将test.txt中输入数据后修改文件名成.dat

使用fread函数从二进制文件中读入数据存入字符数组arr中,并输出

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	FILE *fp = fopen("test.dat", "rb");//只读方式打开,且读的是二进制文件
	if (fp == NULL)
	{
		perror("fopen");
		return 1;
	}
	char arr[7] = { 0 };
	fread(arr, sizeof(arr[0]), sizeof(arr), fp);
	printf("%s", arr);
	// arr : 将文件读取到内存的位置
	// sizeof(arr[0]) : 读取的元素字节大小
	// sizeof(arr) : 读取元素的个数,
	// 读取字节个数是 sizeof(arr) * sizeof(arr[0])
	// fp : 文件指针
	fclose(fp);
	fp = NULL;
	return 0;
}

运行结果如下:

8、fwirte

复制代码
size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
  1. 将数据块写入流
  2. 从ptr指向的内存块向流中的当前位置写入含有count个元素的数组,每个元素的大小为size字节
  3. 流的位置指示器按写入的总字节数前进。
  4. 在内部,该函数将ptr指向的块解释为一个无符号char类型的(大小*计数)元素数组,并将它们顺序写入流,就像每个字节都调用了fputc一样。

本函数由4个参数(与fread类似)

  1. ptr指向要写入的元素数组的指针,转换为const void*。
  2. size要写入的每个元素的大小(以字节为单位)。
  3. size_t是一个无符号整数类型。
  4. count元素的数量,每个元素的大小为字节。
  5. size_t是一个无符号整数类型。
  6. stream指向指定输出流的FILE对象的指针。

我们使用fwirte函数向二进制文件test.dat写入字符串hello,操作如下:

cpp 复制代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	FILE *fp = fopen("test.dat", "wb");//只写方式打开,且写的是二进制文件
	if (fp == NULL)
	{
		perror("fopen");
		return 1;
	}
	char arr[7] = { "hello" };
	fwrite(arr, sizeof(arr[0]), sizeof(arr), fp);
	// arr : 将文件读取到内存的位置
	// sizeof(arr[0]) : 读取的元素字节大小
	// sizeof(arr) : 读取元素的个数,
	// 读取字节个数是 sizeof(arr) * sizeof(arr[0])
	// fp : 文件指针
	fclose(fp);
	fp = NULL;
	return 0;
}

检验:将test.dat后缀改成txt文件,打开发现更改成功

如果我的博客能给您带来启发,请不吝点赞、评论和收藏,也欢迎您关注我的博客。

如果你喜欢这篇文章,别忘了留下你的感想和建议,让我知道你的想法。同时,也请继续关注我的博客,我们不见不散!

最后,愿每一位读到这里的你,都能拥有一个充实而美好的每一天。不管世界怎样变化,保持学习,保持热爱,保持对生活的好奇心,我们的故事,还在继续......

相关推荐
谈谈叭24 分钟前
Javascript中的深浅拷贝以及实现方法
开发语言·javascript·ecmascript
lx学习25 分钟前
Python学习26天
开发语言·python·学习
大今野1 小时前
python习题练习
开发语言·python
爱编程的鱼1 小时前
javascript用来干嘛的?赋予网站灵魂的语言
开发语言·javascript·ecmascript
捕鲸叉2 小时前
C++设计模式和编程框架两种设计元素的比较与相互关系
开发语言·c++·设计模式
未知陨落3 小时前
数据结构——二叉搜索树
开发语言·数据结构·c++·二叉搜索树
大波V53 小时前
设计模式-参考的雷丰阳老师直播课
java·开发语言·设计模式
无敌最俊朗@3 小时前
unity3d————接口基础知识点
开发语言·c#
一丝晨光4 小时前
gcc 1.c和g++ 1.c编译阶段有什么区别?如何知道g++编译默认会定义_GNU_SOURCE?
c语言·开发语言·c++·gnu·clang·gcc·g++
南城花随雪。4 小时前
Spring框架之装饰者模式 (Decorator Pattern)
java·开发语言·装饰器模式