C语言【文件操作 2】

发布于:2024-05-10 ⋅ 阅读:(24) ⋅ 点赞:(0)

前言

在前面的文章我们讲解了文件操作的基础:点击此处浏览前文下面正式讲解文件的操作函数
注意:因为本章讲解的文件操作,所以大多数函数使用环境默认是文件!!!

顺序读写函数的介绍

函数名 功能 适用于
fgetc 字符输⼊函数 所有输入流
fputc 字符输出函数 所有输出流
fgets 文本行输入函数 所有输入流
fputs 文本行输出函数 所有输出流
fscanf 格式化输⼊函数 所有输入流
fprintf 格式化输出函数 所有输出流
fread ⼆进制输⼊ 文件
fwrite 二进制输出 文件

上面说的适用与所有输入流一般指的是适用于标准输入流与其他输入流(例如文件输入流);所有输出流指的是适用于标准输出流与其他输出流(例如文件输出流)。

fputc && fgetc

fputc

将一个字符输出到文件

int fputc(int c, FILE* stream);

参数为什么是int类型呢?

因为传递的是ASCII码值

为什么会返回int类型的值呢?返回的是什么呢?
cpp网站是这样写的:

On success, the character written is returned.
If a writing error occurs, EOF is returned and the error indicator (ferror) is set.

大致意思就是:

如果写入成功,返回被写入的字符的ASCII码值
如果写入失败,返回EOF并设置错误提示符

例子:

#include<stdio.h>

int main()
{
	FILE* pf = fopen("text.txt", "w");//只写
	if (pf == NULL)
	{
		perror("fopen");//如果错误会在屏幕上打印错误原因
	}
	for (char c = 'A'; c <= 'Z'; c++)
	{
		fputc(c, pf);//将字符输入到文件中
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

在这里插入图片描述

fgetc

从文件中读取一个字符

int fgetc(FILE* stream)

返回的是ASCII码值

关于fgetc的返回值cpp网站是这样写的

On success, the character read is returned (promoted to an int value).
The return type is int to accommodate for the special value EOF, which indicates failure:
If the position indicator was at the end-of-file, the function returns EOF and sets the eof indicator (feof) of stream.
If some other reading error happens, the function also returns EOF, but sets its error indicator (ferror) instead.

大致意思是:

如果读取成功,返回被读取字符的ASCII码值;
若读取失败或文件光标已经到了文件末尾(就是没字符可以读了),则会返回EOF

例子:

#include<stdio.h>
int main()
{
	FILE* pf = fopen("text.txt", "r");//只读
	if (pf == NULL)
	{
		perror("fopen");//如果错误会在屏幕上打印错误原因
	}
	int c;
	while ((c = fgetc(pf)) != EOF)
	{
		printf("%c ", c);
	}

	fclose(pf);
	pf = NULL;

	return 0;
}

在这里插入图片描述

fputs && fgets

fputs

将字符串输出到文件

int fputs ( const char * str, FILE * stream );

关于返回值

cpp网站是这样写的:

On success, a non-negative value is returned.
On error, the function returns EOF and sets the error indicator (ferror).

大致意思:

输出成功,返回一个非负数;
输出失败,返回EOF

例子:

#include<stdio.h>
int main()
{
	FILE* pf = fopen("text.txt", "w");//只写
	if (pf == NULL)
	{
		perror("fopen");//如果错误会在屏幕上打印错误原因
	}
	char str[100] = "Hello World";
	fputs(str, pf);//数组名是数组首元素地址
	fclose(pf);
	pf = NULL;
	return 0;
}

在这里插入图片描述

fgets

读取指定位置范围内的字符串

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

str:用于接收字符串
num:一次读num-1个字符(fgets会默认在第num处存放’\0’)

关于返回值
cpp网站是这样写的:

On success, the function returns str.
If the end-of-file is encountered while attempting to read a character, the eof indicator is set (feof). If this happens before any characters could be read, the pointer returned is a null pointer (and the contents of str remain unchanged).
If a read error occurs, the error indicator (ferror) is set and a null pointer is also returned (but the contents pointed by str may have changed).

大致意思就是:

读取成功,返回str的地址;
读取失败或文件已到末尾,返回NULL;

例子:

#include<stdio.h>
int main()
{
	FILE* pf = fopen("text.txt", "r");//只读
	if (pf == NULL)
	{
		perror("fopen");//如果错误会在屏幕上打印错误原因
		return;
	}
	char buf1[100] = { 0 };
	char* str1;
	str1 = fgets(buf1, 12, pf);//这是我明确知道文件有多少个元素
	printf("明确知道:");
	printf("%s", str1);

	printf("\n");
	rewind(pf);//将光标返回文件初始位置

	//假设我们不知道文件内有多少个元素
	char buf2[100] = { 0 };
	char* str2;

	printf("并不明确:");
	while ((str2 = fgets(buf2, 2, pf)) != NULL)
	{
		printf("%s", str2);
	}

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

在这里插入图片描述

fprintf && fscanf

fprintf

将数据以格式化的形式输出到文件

int fprintf ( FILE * stream, const char * format, ... );

fprintfprintf很像,只是printf是输出到标准输出流(屏幕);而·printf是可以输出到指定输出流中

例子:

#include<stdio.h>
typedef struct st
{
	char _Name[20];
	int _Score;
	char _SId[17];
}Stu;

int main()
{
	Stu student = { "zhangsan" , 99, "202300002024" };
	FILE* pf = fopen("text.txt", "w");//只写
	if (pf == NULL)
	{
		perror("fopen");//如果错误会在屏幕上打印错误原因
	}

	fprintf(pf, "%s %d %s", student._Name, student._Score, student._SId);

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

在这里插入图片描述

fscanf

从文件输出格式化的数据

int fscanf ( FILE * stream, const char * format, ... );

同理,fscanfscanf也是很相似的;只不过scanf是从标准输入流(键盘)得到数据,fscanf是从指定的输入流中得到数据

例子:

#include<stdio.h>
typedef struct st
{
	char _Name[20];
	int _Score;
	char _SId[17];
}Stu;

int main()
{
	FILE* pf = fopen("text.txt", "r");//只读
	if (pf == NULL)
	{
		perror("fopen");//如果错误会在屏幕上打印错误原因
	}
	Stu x = { 0 };
	fscanf(pf, "%s %d %s", x._Name, &(x._Score), x._SId);
	printf("%s %d %s", x._Name, x._Score, x._SId);

	fclose(pf);
	pf = NULL;

	return 0;
}

在这里插入图片描述
注意:上面的函数可以使用到任意的指定流中;
当然也要遵守语法:该是输出流给输出流,该是输入流给输入流

就拿fprintf举例

#include<stdio.h>
typedef struct st
{
	char _Name[20];
	int _Score;
	char _SId[17];
}Stu;
int main()
{
	Stu student = { "zhangsan" , 99, "202300002024" };
	FILE* pf = fopen("text.txt", "w");//只写
	if (pf == NULL)
	{
		perror("fopen");//如果错误会在屏幕上打印错误原因
	}

	fprintf(stdout, "%s %d %s", student._Name, student._Score, student._SId);
	//stdout是标准输出流

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

在这里插入图片描述

fwrite && fread

这两个函数只能用文件流(也就是只能输入输出到文件)

fwrite

以二进制的形式输出数据到文件(只能输入到文件)

size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );

ptr->要输入的数据
size->数据的大小
count->数据的个数

例子:

#include<stdio/h>
int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	FILE* pf = fopen("text.txt", "wb");//只写(以二进制形式)
	if (pf == NULL)
	{
		perror("fopen");//如果错误会在屏幕上打印错误原因
	}

	fwrite(arr, sizeof(arr[0]), 10, pf);

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

在这里插入图片描述

fread

以二进制的形式从文件中读取数据

size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );

ptr->用于接收数据
size->数据的大小
count->数据的个数

关于返回值

cpp网站是这样写的

The total number of elements successfully read is returned.
If this number differs from the count parameter, either a reading error occurred or the end-of-file was reached while reading. In both cases, the proper indicator is set, which can be checked with ferror and feof, respectively.
If either size or count is zero, the function returns zero and both the stream state and the content pointed by ptr remain unchanged.
size_t is an unsigned integral type.

大致意思为:

如果读取成功,返回成功读取的元素个数。
如果这个数字与 count 参数不同,要么是发生了读取错误,要么是在读取过程中到达了文件终点。
如果 size 或 count 均为零,函数返回零,流状态和 ptr 指向的内容均保持不变。

例子:

#include<stdio.h>

int main()
{
	FILE* pf = fopen("text.txt", "rb");//只读(以二进制形式)
	if (pf == NULL)
	{
		perror("fopen");//如果错误会在屏幕上打印错误原因
	}
	int arr[10] = { 0 };
	fread(arr, sizeof(arr[0]), 10, pf);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", arr[i]);
	}

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

在这里插入图片描述

文件的随机读写

fseek函数

根据文件指针的位置和偏移量来定位文件指针。

int fseek ( FILE * stream, long int offset, int origin );

偏移量

文件指针所指向的位置距离文件起始位置有多少个数据

文件起始位置有三种(下列表格在cpp网站的fseek函数中)

Constant Reference position
SEEK_SET Beginning of file
SEEK_CUR Current position of the file pointer
SEEK_END End of file *

SEEK_SET:文件的开始位置
SEEK_CUR:文件指针当前的位置
SEEK_END:文件的末尾
如果fseek给的起始位置是SEEK_END,那么访问前面的元素,偏移量就要给负数

例子:

#include<stdio.h>
int main()
{
	FILE* pFile;
	pFile = fopen("text.txt", "w");
	fputs("This is an apple.", pFile);
	fseek(pFile, 9, SEEK_SET);
	fputs(" sam", pFile);
	fclose(pFile);
	return 0;
}

在这里插入图片描述
在这里插入图片描述
这是为什么呢?
我们来看图吧。
在这里插入图片描述

ftell函数

返回文件指针相对于起始位置的偏移量

long int ftell ( FILE * stream );

例子:

#include<stdio.h>
int main()
{
	FILE* pf = fopen("text.txt", "r");//只读
	if (pf == NULL)
	{
		perror("fopen");//如果错误会在屏幕上打印错误原因
	}

	for (int i = 0; i < 5; i++)
	{
		fgetc(pf);
	}
	printf("偏移量为%d ",ftell(pf));
	fclose(pf);
	pf = NULL;

	return 0;
}

在这里插入图片描述

rewind函数

让文件指针返回到文件的起始位置

void rewind ( FILE * stream );

前面的例子也使用过:

#include<stdio.h>
int main()
{
	FILE* pf = fopen("text.txt", "r");//只读
	if (pf == NULL)
	{
		perror("fopen");//如果错误会在屏幕上打印错误原因
		return;
	}
	char buf1[100] = { 0 };
	char* str1;
	str1 = fgets(buf1, 18, pf);//这是我明确知道文件有多少个元素
	printf("明确知道:");
	printf("%s", str1);

	printf("\n");
	rewind(pf);//将光标返回文件初始位置

	//假设我们不知道文件内有多少个元素
	char buf2[100] = { 0 };
	char* str2;

	printf("并不明确:");
	while ((str2 = fgets(buf2, 2, pf)) != NULL)
	{
		printf("%s", str2);
	}

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

在这里插入图片描述

文件的结束判断

被错误使用的feof

牢记:在文件读取的过程中,不能用feof函数的返回值来直接判断文件是否结束。
feof的作用是:当文件已经读取结束时,判断结束的原因是否为“遇到文件尾部结束”。

文本文件读取是否结束。判断返回值是否为EOF (fgetc),或NULL(fgets)。
二进制文件读取是否结束,判断返回值是否小于实际要读的数。

cpp的网站->https://cplusplus.com/

结语

最后感谢您能阅读完此片文章,如果有任何建议或纠正欢迎在评论区留言。如果您认为这篇文章对您有所收获,点一个小小的赞就是我创作的巨大动力,谢谢!!!