【文件指针+文件顺序读写操作函数】

1.文件的打开和关闭

2.文件操作函数

1.文件的打开和关闭

1.1 什么是文件指针?

每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名
字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统
声明的,取名FILE.

假如:我们要操作一个文件,名为text.txt ,首先要打开文件,打开文件的同时,操作系统会自动为该文件创建一个文件信息区,专门用来记录该文件的信息。

在这里插入图片描述
文件信息区的每一个信息与text.txt的信息是一一对应的。而该文件信息区名为struct _iobuf,又被重命名为 FILE 。

所以FILE其实就是文件信息区。

每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,使用者不必关心细节。

一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。

下面我们可以创建一个FILE*的指针变量:

FILE* pf; 文件指针变量

通过该文件指针变量,我们就可以读写文件中的信息。

文件在读写之前,需要打开文件

//打开文件
FILE * fopen ( const char * filename, const char * mode );

读写文件完成后,需要关闭文件:

//关闭文件
int fclose ( FILE * stream );

文件的打开方式如下:

在这里插入图片描述
举个例子:

#include <stdio.h>
int main ()
{
 //打开文件
FILE* pFile = fopen ("text.txt","w");
 //文件操作
 if (pFile!=NULL)
{
  fputs ("fopen",pFile);
  //关闭文件
  fclose (pFile);
}
 return 0;
}

该段代码的意思是:打开一个文件叫text.txt,以写的形式打开。意味着向文件中写入信息。具体是怎么写的,下面会讲到。
写完信息后关闭文件,fclose(pFile),pFile就是一个文件指针。

文件指针就是用来操作文件的,假如我们需要对文件进行写入的操作,就使用文件指针打开该文件并定义"写"的操作。

2.文件操作函数

在这里插入图片描述

2.1 fgetc函数和fputc函数

fgetc函数和fputc函数是针对字符的输入输出的。

int fgetc(FILE* stream);
//从流中读取字符,返回读到的ascii码值

流是什么呢?可以把流理解成水流,水流到尽头,就是一个蓄水池。一个蓄水池就相当于一个存储大量文件的区域。文件也类似,从流中(文件信息区)中读取文件,fgetc返回读到的ascii码值。

int fputc(int character, FILE* stream);
//把字符character 写入流中

fputc是将一个字符写入文件中。一次写入一个字符,返回成功写入的字符的个数。

举个例子:

int main()
{
	FILE* pf =fopen("text.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 0;
	}
	//写入字符
	char ch = 0;
	for (ch = 'a'; ch <= 'z'; ch++)
	{
		fputc(ch, pf);
	}

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

先打开text.txt文件,如果不存在该文件,则会新建一个文件("w"写入的形式会新建一个文件,但是以"r"的形式打开文件,如果文件不存在,会读取文件失败,返回NULL)

然后向文件中写入a~z个字母。

运行成功,成功写入文件:
在这里插入图片描述

写入成功,现在向文件中读取数据

int main()
{
	FILE* pf = fopen("text.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 0;
	}
	//写入字符
	char ch = 0;
	for (ch = 'a'; ch <= 'z'; ch++)
	{
		int ch = fgetc(pf);
		printf("%c ", ch);
	}

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

读取成功,如下图:
在这里插入图片描述
总结:fgetc函数是向文件指针pf(或者其他名字,由你来定)一次读取一个字符,读取完第一个字符后,指针自动跳到下一个字符。
fputc函数是向pf指向的指针一次写入一个字符。

2.2 fgets函数和fputs函数

int fputs(const char* str, FILE* stream);
向流中写入一行数据,一次性写一行

举个例子:

int main()
{
	FILE* pf = fopen("text.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 0;
	}
	fputs("Hello World","w"); 
	
	fclose(pf);
	pf = NULL;
	return 0;
}

写入成功。
在这里插入图片描述
注意:打开文件进行写入操作时,上一次写入的数据将会被清除。

接下来向从文件中读取数据:

int main()
{
	FILE* pf = fopen("text.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 0;
	}
	//读文件,一次读一行
	char buf[20];
	fgets(buf, 10, pf); // 读10个字节,相当于读9个,最后一个字节留着放\0
	printf("%s\n", buf);
	fclose(pf);
	pf = NULL;
	return 0;
}

注意:当我们读取10个字节时,实际上打印出来只打印前面9个字节的内容,还有一个字节是被用来留着放\0的。

还有一种情况,假如我们需要读取20个字节的数据,然而第一行不足20个字节,fgets读完所有的数据后,即使不够20个字节,就不会再读取了,就停止了。不会跳到第二行继续读。 更说明fges是一次只读取一行。

2.3 fscanf函数和fprintf函数

前面说过,fscanf函数和fprintf函数是格式化输入输出函数。什么是格式化函数呢?
其实格式化函数就是对于不同格式的数据都能够进行输入输出,比如:整型,浮点型,结构体类型等等,这些就是不同格式的数据。

相较于scanf和printf函数,fscanf函数和fprintf只是多了一个参数,即FILE指针所指向的文件。fscanf函数是向FILE的指针指向的文件中读取格式化的数据,fprintf函数是向FILE*的指针指向的文件中写入格式化的数据。

对比如下:

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

举一个简单的例子:
向text.txt文件中写入结构体数据

int main()
{
	FILE* pf = fopen("text.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 0;
	}
	struct S
	{
		char name[20];
		int age;
		float score;
	}s = {"zhangsan",20,99.5f};
	fprintf(pf,"%s %d %f", s.name, s.age, s.score);
	
	fclose(pf);
	pf = NULL;
	return 0;
}

运行成功后,文件中就有了该结构体的数据。

在这里插入图片描述
对于fscanf来说亦是如此:

在这里插入图片描述
以读的方式打开该文件,对其中的数据进行读取。读取后,打印出来看即可。

s.name不用&的原因是,s.name是一个数组名,表示首元素地址,不需要&,而其他的age和score则需要&。

前面说过,这几个函数都是适用于所有输入流输出流,那么就包括了键盘(标准输入流),屏幕(标准输出流)。

int main()
{
	int ch = fgetc(stdin);
	fputc(ch, stdout);
}

此时,我们会从键盘中读取一个字符,写入到屏幕中。
在这里插入图片描述
对于其他函数也是如此。仍可以从键盘中读取数据,写入到屏幕上。

2.4 fwrite函数和fread函数

上面提到,fwrite函数和fread函数是以二进制的形式进行写入和读取的。

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

先来看看fwrite在库中的声明。
fwrite函数是向stream这个流中一次写count个大小为size的ptr指向的内容。
看不懂没关系,举个例子:

typedef struct S
{
	char name[20];
	int age;
	float score;
}S;

int main()
{
	S s = { "zhangsan",20,95.5f };
	FILE* pf = fopen("text.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen");
		return 0;
	}
	fwrite(&s, sizeof(S), 1, pf);
	
	fclose(pf);
	pf = NULL;
	return 0;
}

此时我们创建了一个结构体,该结构体有三个成员,我们以二进制写入的形式打开文件进行写入,此时向pf指向的文件中写入s这块空间,一次写入1个sizeof(S)大小的内容。

运行成功后,打开text.txt文件:
在这里插入图片描述

你会发现出了拼音zhangsan,其他的都看不懂,没关系,因为这是二进制形式。
看不懂并不代表代码是错误的。

既然我们看不懂,我们就让编译器来看,下面我们以二进制读取的方式,向文件中读取数据出来。

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

既然是读取,那么就是跟写入相反而已。
从stream流指向的文件中读取ptr这块空间的内容,一次读取count个大小为size个字节的内容。

typedef struct S
{
	char name[20];
	int age;
	float score;
}S;

int main()
{
	S s = { 0 };
	FILE* pf = fopen("text.txt", "rb");
	if (pf == NULL)
	{
		perror("fopen");
		return 0;
	}
	fread(&s, sizeof(S), 1, pf);
	printf("%s %d %f", s.name, s.age, s.score);

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

此时我们向pf流指向的文件中读取s这块空间的内容,一次读取1个大小为sizeof(S)个字节的内容。读取成功后,我们就打印出来看看。
在这里插入图片描述
打印结果确实符合预期。

总结:fwrite 和fread函数是向文件中以二进制的形式写入和读取文件的。

  • 32
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 37
    评论
在C++中,我们可以使用文件流来读写二进制文件。以下是一个简单的示例: 写入二进制文件: ```c++ #include <iostream> #include <fstream> int main() { std::ofstream outfile("data.bin", std::ios::binary); if (outfile.is_open()) { int number = 10; outfile.write(reinterpret_cast<const char*>(&number), sizeof(number)); outfile.close(); } else { std::cerr << "Unable to open file for writing" << std::endl; } return 0; } ``` 首先,我们使用`std::ofstream`来打开一个文件,指定文件名和打开方式`std::ios::binary`。然后,我们使用`write()`函数来写入一个整数。`reinterpret_cast`用于将整数指针强制转换为字符指针,以便在文件中将其写入为字节。最后,我们关闭文件。 读取二进制文件: ```c++ #include <iostream> #include <fstream> int main() { std::ifstream infile("data.bin", std::ios::binary); if (infile.is_open()) { int number; infile.read(reinterpret_cast<char*>(&number), sizeof(number)); std::cout << "Number: " << number << std::endl; infile.close(); } else { std::cerr << "Unable to open file for reading" << std::endl; } return 0; } ``` 我们使用`std::ifstream`打开文件,指定文件名和打开方式`std::ios::binary`。然后,我们使用`read()`函数来读取整数。`reinterpret_cast`用于将字符指针强制转换为整数指针,以便从文件中读取字节并将其转换为整数。最后,我们关闭文件并输出读取的整数。 需要注意的是,在读写二进制文件时,我们需要注意数据的字节顺序(大端序或小端序),以免在不同的平台上出现问题。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 37
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

邓富民

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值