目录
- 1.文件的随机读写
- 1.1 fseek
- 1.2 ftell
- 1.3 rewind
 
- 2. 文件结束的判定
- 2.1 文本文件读取结束的判断
- 2.2 二进制文件读取结束的判断
 
- 3. 文件缓冲区
1.文件的随机读写
1.1 fseek
根据⽂件指针的位置和偏移量来定位⽂件指针。
- 函数原型:
int fseek (FILE * stream, long offset, int origin);
-  stream:一个指向文件流的指针。
-  offset:距离文件参考位置的偏移量。
-  origin:文件指针的参考位置。- 文件的参考位置有如下三种 :
  
- SEEK_SET :文件的开头。
- SEEK_CUR :文件指针的当前位置。
- SEEK_END :文件的结束位置 。
 
- 文件的参考位置有如下三种 :
例子:
#include <stdio.h>
int main()
{
	FILE* pFile = fopen("example.txt", "wb");
	fputs("This is an apple.", pFile);
	fseek(pFile, 9, SEEK_SET);//9是距离文件起始的偏移量,表示将文件指针移到距离文件开头偏移量为9的地方,即字符串中n的位置,则下一次执行的文件操作将从n的位置开始
	//fseek有三个位置常量
	//SEEK_SET 文件起始位置 偏移量为0
	//SEEK_CUR 文件指针的当前位置
	//SEEK_END 文件结束位置 使用时偏移量可以是负数,表示向左偏移
	fputs(" sam", pFile);
	fclose(pFile);
	return 0;
}
- 输出结果 :
  
- 返回值 : 如果成功,函数返回0,失败则返回非0值。
1.2 ftell
返回⽂件指针相对于起始位置的偏移量。
- 函数原型 :
long ftell (FILE * stream);
- stream: 一个指向文件流的指针。
- 返回值 :返回文件指针相对于起始位置的偏移量。
1.3 rewind
让⽂件指针的位置回到⽂件的起始位置。
- 函数原型 :
void rewind (FILE * stream);
- stream: 一个指向文件流的指针。
例子(ftell 和 rewind):
#include <stdio.h>
int main()
{
	int position = 9;
	int n = 0;;
	char buffer[27];//不初始化字符串里就没有\0,初始化会把里面全变成\0
	FILE* pFile = fopen("myfile.txt", "w+");
	for (n = 'A'; n <= 'Z'; n++)
		fputc(n, pFile);
	rewind(pFile); //rewind是让文件指针的位置回到文件的起始位置
	position = ftell(pFile);//ftell是返回文件指针相对于起始位置的偏移量,返回类型是long
	printf("%d\n", position);
	fread(buffer, 1, 26, pFile);
	//(字符串的地址,类型大小,读取个数,流的地址)
	fclose(pFile);
	buffer[26] = '\0';//fread 并不会添加\0
	printf(buffer);
	return 0;
}
- 输出结果(文件) :
  
- 输出结果(屏幕):
  
2. 文件结束的判定
2.1 文本文件读取结束的判断
⽂本⽂件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )。
例如 :
- fgetc读取结束返回EOF,判断返回是否是EOF。
- fgets读取结束返回NULL,判断返回是否是NULL。
例子 :
#include <stdio.h>
#include <stdlib.h>
 
int main()
{
	 int c; // 注意:int,⾮char,要求处理EOF 
	 FILE* fp = fopen("test.txt", "r");
	 if(fp == NULL) 
	 {
		 perror("File opening failed");
		 return EXIT_FAILURE;
	 }
	 //fgetc 当读取失败的时候或者遇到⽂件结束的时候,都会返回EOF 
	 while ((c = fgetc(fp)) != EOF) // 标准C I/O读取⽂件循环 
	 { 
		 putchar(c);
	 }
	 //判断是什么原因结束的 
	 if (ferror(fp))
	 	puts("I/O error when reading");
	 else if (feof(fp))
	 	puts("End of file reached successfully");
	 
	 fclose(fp);
}
2.2 二进制文件读取结束的判断
⼆进制⽂件的读取结束判断,判断返回值是否⼩于实际要读的个数。
例如 :
- fread读取结束返回成功读取的个数,判断返回值是否⼩于实际要读的个数。
例子 :
#include <stdio.h>
 
enum { SIZE = 5 };
int main()
{
	 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);
}
3. 文件缓冲区
ANSIC标准采⽤“缓冲⽂件系统”处理的数据⽂件的,所谓缓冲⽂件系统是指系统⾃动地在内存中为
 程序中每⼀个正在使⽤的⽂件开辟⼀块“⽂件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓
 冲区,装满缓冲区后才⼀起送到磁盘上。如果从磁盘向计算机读⼊数据,则从磁盘⽂件中读取数据输
 ⼊到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓
 冲区的⼤⼩根据C编译系统决定的。
 
 代码示例 :
#include <stdio.h>
#include <windows.h>
//VS2019 WIN11环境测试 
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在关闭文件的时候,也会刷新缓冲区 
	 pf = NULL;
	 return 0;
}
- 结论 :因为有缓冲区的存在,所以C语言在操作文件时,需要刷新缓冲区或者关闭文件(指fclose),如果不做这样的操作,可能导致读写文件的问题,所以在台式电脑断电的时候可能会丢失数据(没来得及将缓冲区的数据输入文件中)。



















