文件操作(二)——文件函数

文章目录

前言

        1.对于“流”的基本理解

        2.文件的顺序读写

                2.1 适用于所有“流”的函数

                        2.1.1 字符操作函数fputc和fgets

                        2.1.2 字符串操作函数fgets和fputs

                        2.1.3 格式化数据函数fprintf和fscanf

                2.2 只适用于文件的函数

                        2.2.1 二进制数据函数fwrite和fread

                2.3 *格式化数据与字符串之间的转换存储

                        2.3.1 sprintf函数与sscanf函数

        3.文件的随机读写

                3.1 fseet函数

                3.2 ftell函数

                3.3 rewind函数

前言

        我们已经知道可以将数据存放到文件中进行储存,但是数据的类型却又很多种,我们针对这些不同类型的数据有着不同的操作函数,这些函数以特定的方式将数据写入文件、读取到内存。

对于流的基本理解

        流是磁盘或其它外围设备中存储的数据的源点或终点。有输入流和输出流。在我们输入数据和输出数据的时候,是不用考虑输入的内容最终回到哪,如果每个数据均考虑其来龙去脉,这样将会增加程序员的负担,有了“流”的概念,我们只需要考虑输入数据,具体数据会以什么方式呈现到什么地方则由“流”来决定。

C程序运行默认打开三个流

FIRE* stdin			标准输入流(键盘)
FIRE* stdout		标准输出流(屏幕)
FIRE* stderr		标准错误流

文件的顺序读写 —— 适用于所有流的函数

 一、字符操作函数 - fputc和fgets

1.fputc函数

int fputc( int c, FILE *stream );

int c:为写入的字符,为int类型是因为放入的是ASCII码值
FILE *stream:文件指针

        该函数针对单个字符进行操作,若写入成功则其返回值为所写入字符的ASCII码值,若写入失败或写入结束均返回EOF。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
	//打开文件
	FILE* pf = fopen("d:\\users\\rich\\桌面\\test.txt", "w");

	//判断是否打开成功
	if (pf == NULL)
	{
		perror(NULL);			//判断错误
		return 1;
	}

	char i = 0;
	for (i = 'a'; i <= 'z'; i++)
	{
		fputc(i, pf);
	}

	fclose(pf);		//关闭文件
	pf = NULL;		//及时置空,防止其变成野指针
	return 0;
}

成功写入文件

 2.fgetc函数

int fgetc( FILE *stream );

FILE *stream:文件指针

        该函数可将写入文件的数据读取出来。若读取成功,其返回值为读取到数据的ASCII码值,若读取失败或结束则返回EOF。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
	//打开文件
	FILE* pf =fopen("d:\\users\\rich\\桌面\\test.txt", "r");

	//判断是否打开成功
	if (pf == NULL)
	{
		perror(NULL);			//判断错误
		return 1;
	}

	int cmp = 0;
	while ((cmp = fgetc(pf)) != EOF)
	{
		printf("%c ", cmp);
	}

	fclose(pf);
	pf = NULL;

	return 0;
}

读取并打印

二、字符串操作函数 - fgets和fputs

1.fputs函数

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

const char *string:为写入的字符串
FILE *stream :是文件指针变量

        该函数可将字符串写入文件当中,若写入成功则返回一个非负的值,若失败时则返回EOF。如下代码,我们用变量、n来承担函数的返回值,通过调试发现n的值为0。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
	//打开文件
	FILE* pf = fopen("d:\\users\\rich\\桌面\\test.txt", "w");

	//判断是否打开成功
	if (pf == NULL)
	{
		perror(fopen);			//判断错误
		return 1;
	}

	int n = fputs("hello world", pf);

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

成功写入

2.fgets函数

char *fgets( char *string, int n, FILE *stream );

char *string:读取的字符串放入的地方
int n:读取的个数,实际读取的比自己希望的个数小1,因为要默认放一个 \0
FILE *stream :是文件指针变量

        该函数可以读取写入文件的字符串,若读取成功则返回存放读取后存放字符串的地址,若读取失败则返回NULL。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
	//打开文件
	FILE* pf = (FILE*)fopen("d:\\users\\rich\\桌面\\test.txt", "r");

	//判断是否打开成功
	if (pf == NULL)
	{
		perror(fopen);			//判断错误
		return 1;
	}

	char arr[30];
	char* p = fgets(arr, 5, pf);
	printf("%s\n", arr);

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

读取结果:代码中需要读取5个字符,实际读取到4个字符和一个 ‘\0’

三、格式化数据函数 - fprintf和fscanf

1.fprintf函数

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

FILE *stream :文件指针变量
const char* format[, argument]...:与printf的参数类似,需要写入的类型,需要写入数据的名称

        该函数可以存储格式化数据,各种类型均可存储,由于类型比较多,所以传参的时候需要传数据的类型、数据名。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

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

int main()
{
	struct S s = { "zhangsan",18,149.5f };
	//打开文件
	FILE* pf = fopen("d:\\users\\rich\\桌面\\test.txt", "w");

	//判断是否打开成功
	if (pf == NULL)
	{
		perror(fopen);			//判断错误
		return 1;
	}

	int n = fprintf(pf, "%s %d %f", s.name, s.age, s.score);

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

        成功写入

2.fscanf函数

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

FILE *stream:文件指针
const char* format[, argument]...:与scanf类似,需要取得数据的类型,需要取类型的位置

        读取写入的数据,本函数需要对写入的数据的类型要有了解。

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

int main()
{
	struct S s = { 0 };
	//打开文件
	FILE* pf = fopen("d:\\users\\rich\\桌面\\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", s.name, s.age, s.score);		
    //将读取后放入结构体中的数据,修改流的方向到屏幕上,则相当于打印了

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

         代码中在fscanf函数读取数据存入结构体变量中后,用fprintf函数,将其流的指向修改为“屏幕”,这样就将数据直接打印在屏幕中,和前面“流”的介绍相对应。

*格式化数据与字符串之间的转换存储——不针对文件操作

1.sprintf函数

int sprintf ( char * str, const char * format, ... );

char * str:需要存放数据的地址
const char * format, ... :rintf内容一样,数据类型,数据名

        该函数将格式化数据转化成字符串进行存储。

2.sscanf函数

int sscanf ( const char * s, const char * format, ...);

const char * s:取数据的地址
const char * format, ...:与scanf函数一样,数据类型,数据地址

        该函数将sprintf函数以字符串形式存储的数据以格式化的形式读取出来。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

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

int main()
{
	struct S s = { "zhangsan",18,149.5f };
	char arr[100];
	struct S cmp = { 0 };

	sprintf(arr, "%s %d %f", s.name, s.age, s.score);
	printf("字符串:%s\n", arr);

	sscanf(arr, "%s %d %f", cmp.name, &(cmp.age), &(cmp.score));
	printf("格式化:%s %d %f", cmp.name, cmp.age, cmp.score);

	return 0;
}

文件的顺序读写 —— 只适用于文件的函数

1.fwrite函数

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

const void *buffer::需要写入数据的位置
size_t size:需要写入数据的大小
size_t count:需要写入数据的数量

        该函数可将数据以二进制的形式写入文件当中。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

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

int main()
{
	struct S s = { "zhangsan",18,149.5f};
	//打开文件
	FILE* pf = (FILE*)fopen("d:\\users\\rich\\桌面\\test.txt", "w");

	//判断是否打开成功
	if (pf == NULL)
	{
		perror(fopen);			//判断错误
		return 1;
	}

	unsigned int n = fwrite(&s, sizeof(struct S), 1, pf);

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

        成功写入

 2.fread函数

size_t fread(void* buffer, size_t size, size_t count, file* stream);

void* buffer:读取后放的位置
size_t size:需要写入数据的大小
size_t count:需要写入数据的数量

        该函数可以读取文件中以二进制存储的数据。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

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

int main()
{
	struct S s = { 0 };
	//打开文件
	FILE* pf = fopen("d:\\users\\rich\\桌面\\test.txt", "r");

	//判断是否打开成功
	if (pf == NULL)
	{
		perror(fopen);			//判断错误
		return 1;
	}

	fread(&s, sizeof(struct S), 1, pf);
	printf("%s %d %f\n", s.name, s.age, s.score);

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

        读取到内存后打印

 文件的随机读写

        在上述的一系列函数中,函数都是按照从头到尾的顺序一次性进行下去,若我们想对数据中间有什么操作,用上述函数则无法实现,为了能更加灵活的操作文件中的数据,我们引入了文件的随机读写函数,即按照操作者的意愿进行读写操作。

        假设文件中存放的有字符‘a’、‘b’、‘c’、‘d’、‘e’、‘f’、‘g’、‘h’,我们以函数fgetc想读取到字符‘c’。在读取字符。刚开始时文件指针默认指向起始位置。

         成功读取完字符‘a’后将会,文件指针指向将会下移到下一个字符的位置,即指向‘b’

          成功读取完字符‘b’后将会,文件指针指向将会下移到下一个字符的位置,即指向‘c’,则可以读取到字符‘c’。

         上述顺序读法很显然无法直接一次就读取到字符‘c’。下面就介绍一下随机读取。

1.fseek函数

        该函数按照某个偏移量来读取字符。

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

FILE *stream :是文件指针变量
long offset:偏移的字节数
int origin:从哪个位置开始算偏移量 

        以哪个位置为起点读取,需要设置相应的位置,有以下三种形式:

SEEK_SET起始位置
SEEK_END末尾位置(相对于起始位置偏移量为负数,最后一个元素之后,并不是指向的最后一个元素)
SEEK_CUR当前文件指针的位置

1.相对于起始地址向右偏移2个字节后读取字符‘c’.(偏移量:向某个方向数的第几个元素)

	fseek(p, 2, SEEK_SET);
	char ch = fgetc(p);
	printf("%c\n", ch);			

2.相对于当前位置(字符‘c’的位置)向右偏移3个字节读取字符‘g’。

	fseek(p, 3, SEEK_CUR);
	char ch = fgetc(p);
	printf("%c\n", ch);			

3.以末尾位置为起点向左偏移8个字节读取字符‘a’

 	fseek(p, -8, SEEK_END);
	char ch = fgetc(p);
	printf("%c\n", ch);			

2. ftell函数

        用于返回文件指针相对于起始位置的偏移量(偏移量:简单理解为从左到右为第几个元素)

long ftell( FILE *stream );

参数只需要传一个文件指针

例如计算字符‘c’的偏移量

	fseek(p, 2, SEEK_SET);
	char ch = fgetc(p);
	printf("%c\n", ch);			
	printf("%d\n", ftell(p));	

         字符‘c’为第三个元素,所以计算出其偏移量为3。

3.rewind函数

void rewind ( FILE * stream );

参数只需上传文件指针

        在进行上述随机读写时容易遗忘现在文件指针指向的位置,该函数的作用是让文件指针指向起始位置。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main()
{
	FILE* p = fopen("d:\\users\\rich\\桌面\\test.txt", "r");
	if (p == NULL)
	{
		perror(main);
		return 1;
	}

 	fseek(p, 2, SEEK_SET);
	char ch = fgetc(p);
	printf("%c\n", ch);			//c
	printf("%d\n", ftell(p));	//3

	rewind(p);				//让指针指向起始位置
	ch = fgetc(p);
	printf("%c\n", ch);		//a

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

输出结果:

 

彩蛋

        我们已经知道可以将文件指针移动到末尾位置,又知道如何求偏移量,我们就可以通过这两个函数配合计算出放入文件的数据的大小。

 	fseek(p, 0, SEEK_END);        //让文件指针指向末尾
    printf("%d\n", ftell(p));     //计算起始位置到末尾位置的偏移量(元素个数)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值