文件操作(二)

1.前言

链接: 文件操作(一)前半部分内容在这里

几个小概念:

标准输入/输出流stdin/stdout
所有(指定)输入/输入流文件流;stdin/stdout
格式化数据就是整型,浮点型那样的数据

2.函数对比

2.1.分类说明

scanf

int scanf ( const char * format, … );
Read formatted data from stdin
从标准输入流上读取格式化的数据

fscanf

int fscanf ( FILE * stream, const char * format, … );
Read formatted data from stream
从指定输入流上读取格式化的数据

sscanf

int sscanf ( const char * s, const char * format, …);
Read formatted data from string
在字符串中读取格式化的数据

printf

int printf ( const char * format, … );
Print formatted data to stdout

把数据以格式化的形式打印在标准输出流上

fprintf

int fprintf ( FILE * stream, const char * format, … );
Write formatted data to stream

把数据以格式化的形式打印在指定的输出流上

sprintf

int sprintf ( char * str, const char * format, … );
Write formatted data to string

把格式化的数据转成字符串

2.2.实例说明

对于scanf与printf的使用不过多说明,主要展示后两组函数。
PS:注意包含#define _CRT_SECURE_NO_WARNINGS不然会有安全警告

案例一:

#include <stdio.h>

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

int main()
{
	struct S s = { "张三", 20, 65.5f };
	//想把s中的数据存放在文件中
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写文件 - 是以文本的形式写进去的
	fprintf(pf, "%s %d %f", s.name, s.age, s.score);

	fclose(pf);
	pf = NULL;

	return 0;
}

功能说明:
打开test.txt文件(“w”模式下若文件不存在则新建一个)
使用fprintf向pf写入数据

案例二:

#include <stdio.h>
struct S
{
	char name[20];
	int age;
	float score;
};

int main()
{
	struct S s = { 0 };
	//想从文件test.txt中读取数据放在s中
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件 
	fscanf(pf, "%s %d %f", s.name, &(s.age), &(s.score));

	//打印在屏幕上看看
	//printf("%s %d %f\n", s.name, s.age, s.score);//
	fprintf(stdout, "%s %d %f\n", s.name, s.age, s.score);

	fclose(pf);
	pf = NULL;

	return 0;
}

功能说明:
在案例一的基础上用fscanf从test.txt文件中读取数据到s中
用printf/fprintf打印在屏幕上。printf(…)与fprintf(stdin…)并无区别

案例三:

#include <stdio.h>
int main()
{
	fputc('a', stdout);
	return 0;
}


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


int main()
{
	char buf[200] = { 0 };
	struct S s = { "张三", 20, 65.5f };
	sprintf(buf, "%s %d %f", s.name, s.age, s.score);

	printf("1以字符串的形式: %s\n", buf);//1

	struct S t = {0};
	sscanf(buf, "%s %d %f", t.name, &(t.age), &(t.score));
	printf("2按照格式打印  : %s %d %f\n", t.name, t.age, t.score);//2

	return 0;
}

功能说明:
用sscanf从test.txt中读取数据到字符串buf中
用sprintf把buf打印在屏幕上(当然也可以用printf打印字符串的操作)

3.文件顺序读写回顾

这里以fwrite() fread()二进制读写为例
fwrite
在这里插入图片描述
ptr为要操作的数据的地址,size为单个数据大小
count为数据数量,stream为对应文件地址

实例一:

#include <stdio.h>
int main()
{
	int arr[] = { 1,2,3,4,5 };

	FILE*pf = fopen("test.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//写数据
	int sz = sizeof(arr) / sizeof(arr[0]);
	fwrite(arr, sizeof(arr[0]), sz, pf);//以二进制的形式写进去的

	fclose(pf);
	pf = NULL;

	return 0;
}

功能:以二进制形式把arr数组写到text.txt里面去

实例二:

#include <stdio.h>
int main()
{
	int arr[5] = { 0 };

	FILE* pf = fopen("test.txt", "rb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读数据
	fread(arr, sizeof(arr[0]), 5, pf);//以二进制的形式读出来
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		printf("%d ", arr[i]);//1 2 3 4 5
	}
	fclose(pf);
	pf = NULL;

	return 0;
}

功能:把二进制存储的文件读出来
结果:在这里插入图片描述

PS:因为是顺序读写,所以先读3个再读2个会连续读取,也可以完成功能

#include <stdio.h>
int main()
{
	int arr[5] = { 0 };

	FILE* pf = fopen("test.txt", "rb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读数据
	fread(arr, sizeof(arr[0]), 3, pf);//以二进制的形式读出来
	int i = 0;
	for (i = 0; i < 3; i++)
	{
		printf("%d ", arr[i]);//1 2 3 4 5
	}
	printf("\n");
	fread(arr, sizeof(arr[0]), 2, pf);//以二进制的形式读出来
	int j = 0;
	for (j = 0; j < 2; j++)
	{
		printf("%d ", arr[j]);//1 2 3 4 5
	}


	fclose(pf);
	pf = NULL;

	return 0;
}

结果:在这里插入图片描述

实例三:


int main()
{
	int arr[5] = { 0 };

	FILE* pf = fopen("test.txt", "rb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读数据-以二进制的形式写进去的
	int i = 0;
	while (fread(&arr[i], sizeof(int), 1, pf))
	{
		printf("%d ", arr[i]);
		i++;
	}

	fclose(pf);
	pf = NULL;

	return 0;
}

功能:
实例二的优化写法,因为只要能读出fread就会返回true从而一个一个读,不用提前预设要读多少个。

4.文件的随机读写

4.1.fseek

根据文件指针的位置和偏移量来定位文件指针。
在这里插入图片描述
第一个参数为文件指针;第二个参数是偏移量;
第三个参数有三个可选,为参考位置:起始位置/当前位置/结尾位置

实例:
对于test.txt文件做以下操作
在这里插入图片描述

int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	int ch = fgetc(pf);
	printf("%c\n", ch);

	fseek(pf, 4, SEEK_CUR);
	ch = fgetc(pf);
	printf("%c\n", ch);

	fseek(pf, 5, SEEK_SET);
	ch = fgetc(pf);
	printf("%c\n", ch);

	fseek(pf, -4, SEEK_END);
	ch = fgetc(pf);
	printf("%c\n", ch);

	fclose(pf);
	pf = NULL;

	return 0;
}

在这里插入图片描述
过程:
在这里插入图片描述

4.2.ftell

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

实例:
对于这个文件
在这里插入图片描述

int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	int ch = fgetc(pf);
	printf("%c\n", ch);//a
	fseek(pf, -4, SEEK_END);
	/*fseek(pf, 0, SEEK_END);*/
	printf("%d\n", ftell(pf));

	fclose(pf);
	pf = NULL;

	return 0;
}

在这里插入图片描述
过程
在这里插入图片描述

4.3. rewind

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

实例:
对于文件
在这里插入图片描述

int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	int ch = fgetc(pf);
	printf("%c\n", ch);//a
	fseek(pf, -4, SEEK_END);
	ch = fgetc(pf);
	printf("%c\n", ch);//d

	rewind(pf);
	ch = fgetc(pf);
	printf("%c\n", ch);//a

	fclose(pf);
	pf = NULL;

	return 0;
}

在这里插入图片描述

5.文件读取结束的判定

5.1.被错误使用的 feof

牢记:在文件读取过程中,不能用feof函数的返回值直接来判断文件的是否结束。
feof 的作用是:当文件读取结束的时候,判断是读取结束的原因是否是:遇到文件尾结束。即已经结束后判断结束的原因。
PS:feof与ferror
在这里插入图片描述

  1. 文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )
    例如:
    • fgetc 判断是否为 EOF .
    • fgets 判断返回值是否为 NULL .
    在这里插入图片描述

  2. 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。

实例:

int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读取
	int ch = 0;
	while ((ch = fgetc(pf)) != EOF)
	{
		printf("%c\n", ch);
	}
	//判断是什么原因导致读取结束的
	if (feof(pf))//非0值,遇到文件末尾,正常结束
	{
		printf("遇到文件末尾,读取正常结束\n");
	}
	else if (ferror(pf))
	{
		perror("fgetc");
	}

	return 0;
}

6.文件缓冲区

ANSIC 标准采用“缓冲文件系统” 处理的数据⽂件的,所谓缓冲⽂件系统是指系统⾃动地在内存中为程序中每⼀个正在使⽤的⽂件开辟⼀块“⽂件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才⼀起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。
在这里插入图片描述
打个比喻,同学要问老师问题。如果总是一个一个问,那么老师没法干活或只能给 一个同学答疑。先把问题整理好,憋个5个10个再统一问。这就是文件缓冲区。

7.结语

基本理解+能够使用=学会了
希望有些帮助~~

  • 22
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值