C语言文件操作(2)

目录

五、文件的随机读取或输入:

5.1 fseek函数:

5.2 ftell函数:

5.3 rewind函数: 

六. 文本文件和二进制文件:

七. 文件读取结束的判定:

7.1 错误使用 feof 函数:

7.2 如何判断文件读取是否结束:

7.2.1、文本文件:

7.2.2、二进制文件:

7.3 feof 函数的使用:

八. 文件缓冲区 :


五、文件的随机读取或输入:

所谓文件的随机读取或输入,即可以不按照一定的顺序进行读取或输入比如:

假设一个文件中内容有字符串abcdef,,,最开始读取的时候,文件指针指向字符a,当读取完该字符之后,文件指针就会往后偏移一个

元素,指向字符b,直至把文件中的数据全部读取完毕,在不断操作文件的时候,会有一个定位位置的文件指针不断地发生变化,这是

照一定的顺序进行读取的,那么如何才能做到不按照一定的顺序进行读取呢?

5.1 fseek函数:

根据 文件指针的位置和偏移量 定位文件指针 目前不考虑第三个参数的类型、
int fseek ( FILE * stream, long int offset, int origin );

功能:移动文件指针到一个特定的位置、

第二个参数指的是偏移量:

如果该偏移量是一个正数,则代表的是往后偏移,如果该偏移量是一个负数,则代表的是往前偏移单位是字节、

第三个参数指的是进行偏移时起始位置:

关于进行偏移时的起始位置的选项有三个

SEEK_CUR:表示当前文件指针的位置,即从当前文件指针的位置进行偏移、

SEEK_END:表示文件末尾的位置,即从文件末尾的位置进行偏移、此时文件中的内容已经结束,如果再往后进行偏移的话,不管偏移几

                       个字节,都会因为文件结束从而使得fgetc函数会返回一个EOF,即-1,当使用%c打印int整型-1的时候,打印出来的是空白

SEEK_SET: 表示文件的起始位置,即从文件起始的位置进行偏移、此位置文件内容的起始位置,如果再往前进行偏移的话,不管偏移 

                       几个字节,也是都会因为文件结束从而使得fgetc函数返回一个EOF,即-1,从文件内容的起始位置往前进行偏移,也可以理 

                       解成是文件中的内容结束和从文件末尾的位置往后偏移造成的结果是一样的,当使用%c打印int整型-1的时候,打印出来的

                       都是空白

 例子:

C语言中,关于打开方式来说,不起到绝对的影响,具体还是由后面使用的函数决定,所以:

对于fgets,fgetc函数来说的话,一般使用的是:"r"、

对于fputc,fputs函数来说的话,一般使用的是:"w"、

对于fread函数一般使用的是:"r"或者"rb"、

对于fwrite函数来说的话,一般使用的是:"w"或者"wb"、

但是在C++中可能会造成一些影响,具体的等后面再进行讨论即可。

5.2 ftell函数:

返回当前的文件指针相对于文件内容的起始位置的偏移量、

long int ftell ( FILE * stream );

ftell函数的返回值的类型是long int,即返回值代表的是当前的文件指针相对于文件内容的起始位置的偏移量,单位是字节。

例题:

5.3 rewind函数: 

当前文件指针的位置 回到 文件内容的起始位置、
void rewind ( FILE * stream );

字符串字符二进制的形式写入和以文本的形式写入内容是一样的,本质上都是存储的每个字符的ASCII码值,其他类型的数据,是不一

样的、

六. 文本文件和二进制文件:

根据 数据的组织形式 数据文件 被称为 文本文件 或者 二进制文件。
数据 在内存中以二进制的形式存储 ,如果 不加转换的直接把二进制的信息输出到外存(文件) ,就是 二进制文件。
如果要求 在外存上以ASCII码的形式存储 ,则 需要在存储前转换 ,即把 在内存中的值取出来之后先要进行转换成其对应的ASCII码值 并且
ASCII码值 的形式 存储在外存 中,,以 ASCII字符的形式存储的文件就是文本文件、
一个数据在 文件 中是怎么存储的呢?

字符 一律以 ASCII码 值的 形式 存储 数值型数据 既可以用 ASCII形式存储 ,也可以使用 二进制形式存储。
比如:
已知, 文本文件就是 以ASCII码值的形式进行存储在 文件中的,该 文本文件中的内容都是由 字符构成的,所 看到的每一个数据都是字符类
本质上这些字符都是以该字符对应的ASCII码值进行存储在文件中的一个字符占一个字节,就比如, int类型的整数10000,如果是
ASCII码值的形式存储在文件中的话,那么 在文件中所看到的数据10000都是由字符构成的,所以由 5个字符构成,而每个字符的本质上都
是由该字符对应的ASCII码值进行存储的,所以, 5个字符,每个字符占一个字节,所以共占5个字节、
有  int 类型的 整数10000 ,如果以 ASCII码 的形式输出到 磁盘(硬盘) ,则 磁盘 中占用 5个字节 每个字符一个字节 ),而 二进制形式输出
即,由于 数据在内存中均是以二进制形式存储 ,如果 不加转换的直接输出到外存(磁盘,硬盘) ,就是 二进制文件 ,而 int 类型的整数
10000 ,是一个 整数,类型是int整型,所以占4byte ,则在磁盘上只占 4个字节

测试代码:  

七. 文件读取结束的判定:

7.1 错误使用 feof 函数:

  牢记: 在文件读取过程中, 不能用feof函数的返回值 直接用来判断文件的 是否结束。
而是应用于 当文件读取结束的时候 已经读取结束了 ,判断是 读取失败结束 ,还是 遇到文件尾结束的 ,主要是用来 判断结束的原因、 
既然该函数 不是用来判断文件读取是否结束,那么 应该怎么来判断文件读取结束呢?

7.2 如何判断文件读取是否结束:

7.2.1、文本文件:

文本文件 读取 是否结束 ,是通过 返回值 来判断的、
例如:
1、 fgetc函数:函数在 读取结束,包括 读取失败而结束和遇到文件结尾而结束,返回值都是 EOF正常读取的时候,返回的是 读取到的字符
                        的ASCII码值、
2、 fgets函数:函数在 读取结束的时候,包括 读取失败而结束和遇到文件结尾而结束,返回值都是 空指针NULL正常读取的时候,返回的
                        是 存放字符串的空间的起始位置的地址、

7.2.2、二进制文件:

二进制文件 读取结束判断 ,判断 返回值是否小于实际要读(最大能够读取到的元素个数)的个数。
例如:
fread函数在读取的时候,返回的是 实际读取到的完整的元素的个数,如果读取到的 完整元素的个数 小于 实际要读,指定的元素个数,即最
大能够读取到的元素个数的个数 则这就是最后一次读取,即指读取结束了。

7.3 feof 函数的使用:

例题一、


//写代码,把example.txt文件拷贝一份放在example2.txt中、
//从example.txt文件中读取数据放到example2.txt文件中,读一个写一个、
int main()
{
	FILE* pfread = fopen("example.txt", "r");
	if (pfread == NULL)
	{
		//打开文件example.txt失败
		perror("fopen");
		return 1;
	}
	else
	{
		//打开文件example.txt成功
		FILE* pfwrite = fopen("example2.txt", "w");
		if (pfwrite == NULL)
		{
			//打开文件example2.txt失败
			perror("fopen");
			//打开example.txt文件成功的,打开example2.txt文件失败、
			fclose(pfread);	
			pfread = NULL;
			return 1;
		}
		else
		{
			//打开文件example2.txt成功
			//读写文件
			int ch = 0;
			while ((ch=fgetc(pfread)) != EOF)
			{
				//写入文件
				fputc(ch, pfwrite);
			}
		
			//假设文件example.txt中数据有字符串abcdef,,while里面的fgetc函数读取到字符a之后,指针往后偏移一下,等到第二次fgetc函数的时候, 又读取到字符b之后,把字符b
			//写入了新的文件,然后指针又往后偏移一个元素,此时,字符a就没有被写入新文件中,所以会出错、

			//所以对于文件的操作函数fgets来说,由于该函数会自动偏移文件指针变量的位置,所以一般情况下不要去使用链式访问,容易出错。

			//while ((fgetc(pfread)) != EOF)
			//{
			//	//写入文件
			//	fputc(fgetc(pfread), pfwrite);
			//}

		}
		//关闭文件
		fclose(pfwrite);
		pfwrite = NULL;
	}
	//关闭文件
	fclose(pfread);
	pfread = NULL;
	return 0;
}

例题二、

1、ferror函数:

int ferror ( FILE * stream );

如果是读取失败,即读取错误的话,则返回一个非0的 int 整数否则,则返回一个 int 整数0、

2、feof函数:

int feof ( FILE * stream );

如果是遇到文件结束,即文件末尾的话,则会返回一个非0的 int 整数,,否则,则会返回一个 int 整数0、

一、文本文件的例子:

#include <stdio.h>
#include <stdlib.h>
int main(void)//无参
{
	int c=0;    // 注意:int,非char,要求处理EOF、
	FILE* fp = fopen("test.txt", "r");
	if (!fp)//如果打开文件失败,则返回空指针NULL,空指针NULL本质上就是0,,0代表假,!0,即逻辑取反,则是真、
	{
		//打开文件失败
		perror("File opening failed");
		return 1;
	}
	//fgetc函数当读取失败的时候或者遇到文件结束的时候,都会返回EOF、
	//对于文件操作函数fgetc来说,不要使用链式访问,容易出错、
	while ((c = fgetc(fp)) != EOF)  // 标准C  I/O读取文件循环
	{
		putchar(c);
	}
	//判断是什么原因读取结束的、
	if (ferror(fp))
	{
		puts("I/O error when reading");
	}
	if (feof(fp))
	{
		puts("End of file reached succ	essfully");
	}
	//关闭文件
	fclose(fp);
	fp = NULL;
}

二、二进制文件的例子:

#include <stdio.h>
enum { SIZE = 5 };
int main(void) {
	double a[SIZE] = { 1., 2., 3., 4., 5. };
	FILE *fp = fopen("test.bin", "wb"); // 必须用二进制模式
	fwrite(a, sizeof *a, SIZE, fp); // 写 double 的数组
	fclose(fp);
	double b[SIZE];
	fp = fopen("test.bin", "rb");
	size_t ret_code = fread(b, sizeof *b, SIZE, fp); // 读 double 的数组
	if (ret_code == SIZE) {
		puts("Array read successfully, contents: ");
		for (int n = 0; n < SIZE; ++n) printf("%f ", b[n]);
		putchar('\n');
	}
	else { // error handling
		if (feof(fp))
			printf("Error reading test.bin: unexpected end of file\n");
		else if (ferror(fp)) 
		{
			perror("Error reading test.bin");
		}
	}
	//关闭文件
	fclose(fp);
	fp = NULL;
}

八. 文件缓冲区

  ANSIC 标准 采用 “缓冲文件系统” 处理的 数据文件 的, 所谓缓冲文件系统 是指系统 自动地 内存中 为程序中每一个正在使用的文件开辟一块
“文件缓冲区” 。从 内存 磁盘 输出数据 先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上 。如果 从磁盘向计算机(内存)读入数
,则 从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区) ,然后 再从缓冲区逐个地将数据送到程序数据区(程序变量等) 缓冲区
的大小根据C编译系统决定的。  

测试代码:
#include <stdio.h>
#include <windows.h>
//VS2013 WIN10环境测试
int main()
{
	FILE*pf = fopen("test.txt", "w");
	fputs("abcdef", pf);//先将代码放在输出缓冲区,不会直接写入文件中、
	printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n");
	Sleep(10000);
	printf("刷新缓冲区\n");
	fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘)、
	//注:fflush 在高版本的VS上不能使用了
	printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n");
	Sleep(10000);
	//关闭文件
	fclose(pf);
	//注:fclose在关闭文件的时候,也会刷新缓冲区,即使前面没有主动刷新缓冲区,当关闭文件的时候,
	//fclose函数会先自动进行一次刷新缓冲区,把缓冲区中的内容拿走之后再关闭文件。
	pf = NULL;
	return 0;
	//所以,文件缓冲区是存在的、
}

结论:

因为 有缓冲区的存在 C 语言在操作 文件 的时候,需要做 刷新缓冲区 或者 在文件操作结束的时候关闭文件 ,如果 不做 ,可能导致 读写文件的
问题。
知识点拓展:
一、
void: 本质上的意思是指 无具体类型,比如, void* ,是指 无具体类型的指针,他可以 接收任何类型的数据的地址、
除此之外, void还有 特殊的用途,即: 函数不需要返回或者是函数无参、
比如:
void Add(int x,int y),,此时的 void是指Add函数 不需要返回值,,还有就是:int main( void),此时是指该main函数 无参。
二、
EXIT_FAILUREEXIT_SUCCESS是C语言头文件库中定义的一个 符号常量,在 vc++6.0下 头文件stdlib.h中定义如:
#define EXIT_FAILURE 1
#define EXIT_SUCCESS 0

可以简单的认为这两者都是 int 整型常量即可、

关于文件的知识已经分享完毕,大家记得点赞收藏哦~
  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

脱缰的野驴、

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

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

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

打赏作者

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

抵扣说明:

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

余额充值