【C语言】文件操作-文件的随机读取

文章目录

1、sscanf与sprintf

1.1sprintf

1.2sscanf

2、scanf、fscanf、sscanf区别  

3、文件的随机读取

3.1 fseek()函数

3.2  ftell() 、rewind()  函数

4.被错用的feof 

4.1feof的功能

4.2 判断文件是否结束的方法


1、sscanf与sprintf

1.1sprintf

        sprintf是一个将格式化数据写入字符串的函数。

        如下,sprintf第一个参数是待写入的字符串,后面两个参数和printf一样。整个函数就是把格式化的数据全部转换成字符串放入str中。

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

        如下代码和运行结果,原本结构体中char、int、float类型的数据全部转换成了字符串放到buf里面。

#include<stdio.h>

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

int main()
{
	struct info a= { "zhangsan",30,95.5f };
	char buf[100] = { 0 };

	//把格式化数据转换成字符串,输出到字符数组里面。
	sprintf(buf, "%s %d %f", a.name, a.age, a.score);
	printf(buf);

	return 0;
}

 

1.2sscanf

        sscanf是一个从字符串读取格式化数据的函数。

        其作用是:从 s 读取数据并根据参数格式将它们存储到附加参数给定的位置,就像使用了 scanf 一样,但从 s 而不是标准输入 (stdin) 读取数据。

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

         知道了sprintf的功能,sscanf运行结果业不难猜测,它就是把字符串中的数据,按要求转化成各种格式的数据存到对应的内存中。如下代码和运行结果,第一行运行结果是以字符串的格式输出到屏幕的,第二行是%s  %d  %.2f 格式输出到屏幕的。

#include<stdio.h>

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

int main()
{
	struct info a= { "zhangsan",30,95.5f };
	char buf[100] = { 0 };

	//把格式化数据转换成字符串,输出到字符数组里面。
	sprintf(buf, "%s %d %f", a.name, a.age, a.score);
	printf(buf);

	//从buf中按照格式输入到内存里面
	sscanf(buf, "%s %d %f", a.name, &(a.age), &(a.score));
	printf("\n%s %d %f", a.name, a.age, a.score);

	return 0;
}

2、scanf、fscanf、sscanf区别  

scanf 按照一定的格式从键盘输入数据
printf 按照一定的格式把数据打印到屏幕
适用于标准输入、输出流的格式化输入、输出语句
 
fscanf  按照一定格式从输入流(文件/stdin)输入数据
fprintf 按照一定格式把数据向输出流(文件/stdout)输出数据
适用于所有输入、输出流的格式化输入、输出语句

sscanf 从字符串中按照一定的格式读取数据
sprintf 把格式化的数据按照一定的格式转换成字符串

3、文件的随机读取

        在使用文件的顺序读取的时候,时常会发出疑问:能不能跳着读取数据呢?能不能读了这个数据,再重新读取一次该数据呢?能不能读数据到一半,再从头开始读数据呢?而对文件操作熟悉的同学,都明白这一切都要依靠文件指针的位置。文件指针在何处,就读取何处的数据。 所以,文件的随机读取,本质上就是移动文件指针。

在这里介绍一下C语言自带的几个常量:

SEEK_SET      返回 文件开头的位置

SEEK_CUR     返回 文件指针当前指向的位置

SEEK_END     返回 文件末尾的位置

3.1 fseek()函数

        该函数又被称为 重新定位流位置指示器  ,其作用就是重新定位文件指针的位置,实现文件的随机读取。

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

第一个参数是文件流

第二个参数是偏移量

第三个参数是偏移的起始位置

作用后文件指针指向某个位置(该位置是从偏移的起始位置 origin 开始,偏移了offset个位置之后 的位置)

        如下,只读方式打开"test.txt"文件,该文件里面的内容是“abcdefg”,一开始用fgetc读了一个字符,然后文件指针指向b的位置。

        第二步用fseek函数,将文件指针移到当前位置向后偏移1位的位置,指向 'c' 然后读取一个字符,读出的应该是“c”,打印出来正确。

        第三步是用fseek函数,将文件指针移到文件开头位置向后偏移3位的位置,指向 ‘d’ 然后读取一个字符,读出来应该是'd' ,打印出来正确。

       第四步是用fseek函数,将文件指针移到文件末尾位置向前偏移三位的位置,指向‘e’ ,读出来应该是‘e’ ,打印出来正确。

#include<stdio.h>

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, 1, SEEK_CUR);//文件指针在文件的当前位置,偏移1个字符
	ch = getc(pf);
	printf("%c\n", ch);

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

	fseek(pf, -3, SEEK_END);//从最后往前偏移3个字符读取数据
	ch = fgetc(pf);
	printf("%c\n", ch);

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

3.2  ftell() 、rewind()  函数

         ftell()函数可以获取流中的当前位置。即返回文件指针的当前指向的位置。其只有一个参数,是文件指针。

 long int ftell ( FILE * stream ); 

         rewind()函数可以将流的位置设置为开头。即可以将文件指针指向文件开头。其参数是一个文件指针,调用这个函数后,该指针指向文件初始位置。

  void rewind ( FILE * stream ); 

        如下代码和运行结果,打开一个"test.txt" 文件,其内容是 "abcdefg",首先用fseek函数把文件指针位置从最后往前移三位,即移到了"e"的前面。此时从文件起始位置看过去,该文件指针位置是4(起始位置是0)。ftell读取当前位置,符合预期。然后用rewind,再读取字符,也符合rewind将文件指针指向开头的功能。

#include<stdio.h>

int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen()");
		return 1;
	}

	fseek(pf, -3, SEEK_END);//从最后往前偏移3个字符读取数据

	//返回当前文件指针指向的位置
	int pos = ftell(pf);
	printf("%d\n", pos);

	rewind(pf);//文件指针返回初始位置
	int ch = getc(pf);
	printf("%c\n", ch);

	//关闭文件
	fclose(pf);
	pf = NULL;

	return 0;
}

4.被错用的feof 

4.1feof的功能

        feof 是一个检查文件结尾指示器。其参数是一个文件指针,且要指向文件末尾()。

 int feof ( FILE * stream ); 

        文件读取的过程中,我们常用 feof 来判断文件的读取是否结束。但实际上,这是错误的用法,feof 真正的用法是——当文件读取结束时,来判断:是读取失败而结束,还是读取到文件末尾结束 。feof 的功能,官方说明是:检查是否设置了与关联的文件尾指示器,如果是,则返回与零不同的值。   翻译一下,就是:feof返回非0,那么是读到文件末尾结束。  如果返回0,那么就是读取失败而结束。

        那么如何将文件指针指向文件末尾呢?可以使用fseek函数,也可以使用fgetc,直到读完文件,就到了末尾位置。

#include<stdio.h>

int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (!pf)
	{
		perror("fopen()");
		return 1;
	}

	int ch;
	while (ch = fgetc(pf) != EOF)
	{
		putchar(ch);
	}

	//判断是什么原因结束的
	if (ferror(pf))
	{
		printf("I/O error in reading!\n");
	}
	else if (feof(pf))//正常结束返回非0
	{
		printf("End of file reach successfully!\n");
	}

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

4.2 判断文件是否结束的方法

        文件是否结束,主要也和文件指针关联。

比如,一个文件里的内容是“abcdefghijk”

那么使用 | 代表文件指针

“ab cdefghijk”

“abcde fghijk”

“abcdefghij k”

“abcdefghijk 

        对于上面各种情况,无疑只有最后一种情况是文件结束的,那么此时用该如何来判定呢?仔细想一下,我们使用过的文件顺序读取函数(随机读取在这里使用无意义),不可以是输出函数,因为这类函数会向文件写入内容。所以只能使用输入函数,读取文件的内容,比如 fgetc,fgets,fscanf 等等。

         那么,用这些函数,就要知道,在 文件指针指向文件末尾 文件指针不指向文件末尾 的情况下,其返回值的区别。

文本文件判断结束:
        fgetc如果读取正常, 返回该字符的ASCLL码值,读取失败,返回EOF。
        fgets读取正常,返回存放数据的空间的起始地址,否则返回NULL。
        fscanf读取正常,返回的是格式串指定的数据的个数,读取失败,返回的是小于格式串中指定的数据个数。

二进制文件判断结束:
        fread,正常,返回的是实际读取数据个数,否则返回小于设定的读取数据个数。

       根据这些返回值,用 if 语句判断即可,这里不多赘述啦!!!

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

努力努力再努力.xx

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

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

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

打赏作者

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

抵扣说明:

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

余额充值