文件操作(2)

前言

接着上个文件操作(1)继续讲

1.所有流变为标准流

在这里插入图片描述
如上图所示,有些函数是适用于所有流的,既然这样,那肯定也适用于标准流了,若要用上标准流,这时就要用上stdout与stdin了

int main()
{
	char arr[20] = { 0 };
	fscanf(stdin, "%s", arr);
	fprintf(stdout, "%s", arr);
	return 0;
}

在这里插入图片描述
fscanf(stdin, “%s”, arr)这个表示的是从键盘输入的读取到arr中
fprintf(stdout, “%s”, arr)这个表示的是打印在屏幕上
屏幕和键盘就是标准流了

2.文件的随机读写

为什么在文件中读取数据时,会接着上次读取,而不是每次都从开头开始读取,那是因为有个东西记录了位置,其实背后就是文件指针记录的,所以只要掌握的文件指针的位置,就可以想读取哪里就读取哪里了,实现文件的随机读取。

2.1fssek

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

文件每读取一个就会前进一步,文件指针就会前进一步,这个函数的作用主要是定位文件指针,把文件指针设置在某个位置,origin 是起点,表示把文件指针从origin 的位置向后移offset步,也就是affset个字节,如果offset是负数就表示向前移,而origin 总共只能取三个值,SEEK_CUR表示文件指针当前位置,SEEK_END表示文件指针结尾位置,SEEK_SET表示文件指针开头位置。

int main()
{
	FILE*pf=fopen("text.txt", "w");
	for (char c = 'a'; c <= 'z'; c++)
	{
		fputc(c, pf);
	}
	flose(pf);
	pf = NULL;
	return 0;
}

在这里插入图片描述
先在文件中填充数据,现在开始操作。

int main()
{
	FILE* pf = fopen("text.txt", "r");
	char c = 0;
	c=fgetc(pf);//指向a
	printf("%c", c);

	fseek(pf, 6, SEEK_SET);//从开头后移六个位置
	c = fgetc(pf);
	printf("%c", c);

	fseek(pf, -2, SEEK_END);//最后位置前移2步
	c = fgetc(pf);
	printf("%c", c);

	fseek(pf, -4, SEEK_CUR);//当前位置前移4步
	c = fgetc(pf);
	printf("%c", c);

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

在这里插入图片描述

2.3ftell

long ftell( FILE *stream );

这个函数很简单,返回值就是当前文件指针相对于起始位置的偏移量
还是以文件中为a~z举例

int main()
{
	FILE* pf = fopen("text.txt", "r");
	char c = 0;
	c = fgetc(pf);
	c = fgetc(pf);
	c = fgetc(pf);
	int far = ftell(pf);
	printf("%d", far);

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

在这里插入图片描述
因为fgetc使用了三次,所以理所应当当前文件指针相对于起始位置3个偏移量

2.4 rewind

void rewind( FILE *stream );

这个函数的主要作用是把当前文件指针位置调回到起始位置

int main()
{
	FILE* pf = fopen("text.txt", "r");
	char c = 0;
	c = fgetc(pf);
	printf("%c", c);
	rewind(pf);
	c = fgetc(pf);
	printf("%c", c);
	
	fclose(pf);
	pf = NULL;
	return 0;
}

在这里插入图片描述
这里打印了两个a就可以说明文件指针在第二次就回到了起始位置了

3.文件读取结束的判定

因为fgetc的返回值是那个字符,fgets的返回值是那个数组地址,fread的返回值是读取的字符个数,所以判断读取是否结束时的循环条件为fgetc是否为EOF,fgets是否为NULL,fread的返回值是否小于读取个数。

int main()
{
	FILE* pf = fopen("text.txt", "r");
	char c = 0;
	while ((c = fgetc(pf)) != EOF)
	{
		;
	}
	
	fclose(pf);
	pf = NULL;
	return 0;
}

如上图,循环条件为c = fgetc(pf)) != EOF,那么这样的话,退出循环条件就只有两种可能了,第一正常读取到了结尾,正常结束了,c=EOF了,第二就是读取错误,强制退出了,会返回一个错误码。那如何分辨这两种情况呢,第一是看返回值是不是NULL,第二就是用feof与ferror这两个函数了。

int feof( FILE *stream );
int ferror( FILE *stream );

feof是判断是否读取到文件末尾的函数,如果是读取到结尾了,正常结束了,feof会返回真
ferror是判断是否读取错误的,如果读取错误,就会返回真

int main()
{
	FILE* pf = fopen("text.txt", "r");
	char c = 0;
	while ((c = fgetc(pf)) != EOF)
	{
		;
	}
	//法一
	if (c == EOF)
	{
		printf("正常读取到了结尾\n");
	}
	//法二
	if (feof(pf))
	{
		printf("正常读取到了结尾\n");
	}
	else if (ferror(pf))
	{
		printf("文件读取错误\n");
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

看这个代码,按照常理来说,没什么错误的话,就是正常读取到了末尾,果然是。
在这里插入图片描述
但法一并不可靠,并不是判断是否读到文件末尾和读取错误最好的方法,所以最好还是用法二,下面举一个读取错误的例子,可以r改为w。

int main()
{
	FILE* pf = fopen("text.txt", "w");
	int c = 0;
	while ((c = fgetc(pf)) != EOF)
	{
		;
	}
	//法二
	if (feof(pf))
	{
		printf("正常读取到了结尾\n");
	}
	else if (ferror(pf))
	{
		printf("文件读取错误\n");
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

在这里插入图片描述

4.文件缓冲区

先举个实例

int main()
{
	FILE* pf = fopen("text.txt", "w");
	for (char c = 'a'; c <= 'z'; c++)
	{
		fputc(c, pf);
	}
	pf = fopen("text.txt", "w");
	int c = 0;
	while ((c = fgetc(pf)) != EOF)
	{
		printf("%c",c);
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

在这里插入图片描述
看上面这个程序,我想在同一个程序实现r与w,先存入数据到文件中,在读取打印出,结果却是没有打印,什么原因呢,请直接往下看
在这里插入图片描述

向文件中读取数据或者存入数据时,并不是直接就会传递的,他们中间是有个桥梁的,比如向文件中存入数据时,会先将数据放入文件缓冲区中,等到fclose时,才会放入文件中,所以在程序先先写入数据,再读取数据,是不太可能实现的,这里再看一个实例。

int main()
{
	FILE* pf = fopen("text.txt", "w");
	for (char c = 'a'; c <= 'z'; c++)
	{
		fputc(c, pf);
	}
	Sleep(20000);
	pf = fopen("text.txt", "w");
	int c = 0;
	while ((c = fgetc(pf)) != EOF)
	{
		printf("%c", c);
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

这个程序的中间加入了Sleep函数,意思就是在fputc之后程序暂停一下,你现在去文件那里看一下,你会发现文件那里根本还没有存入数据,如果自己嫌操作麻烦,可以去看一下文件操作(2)的视频,这个现象与我们的分析是一样的,最后fclose之后,文件中就有数据了,因为fclose相当于刷新了一下,缓冲区,把数据全部都放在文件中了。
那有什么函数可以实现文件缓冲区的刷新吗,答案是有的,这个函数就是fflush。可以实现文件缓冲区的刷新。

int main()
{
	FILE* pf = fopen("text.txt", "w");
	for (char c = 'a'; c <= 'z'; c++)
	{
		fputc(c, pf);
	}
	Sleep(10000);
	fflush(pf);
	Sleep(10000);
	pf = fopen("text.txt", "w");
	int c = 0;
	while ((c = fgetc(pf)) != EOF)
	{
		printf("%c", c);
	}
	fclose(pf);
	pf = NULL;
	return 0;
}

如上,增加fflush这个函数,这次用与上次相同的操作,你就会发现,第二次休眠中,文件中已经就有数据了。这就是文件缓冲区。
那为什么要有文件缓冲区呢,因为把数据先放在一起,在一起打包带走,要比每次都运输一点点的效率要高。比如日常生活中,明明可以跑一遍就做完了,你愿意跑10遍吗?
这也是为什么文件打开了一定要fclose的原因,要刷新缓冲区嘛。

总结

好了,C语言文件操作就结束了!!!!

  • 12
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值