C语言文件操作(下)

六.文件的随机读写函数

1.fseek:定位文件指针

C语言文件操作(下)_第1张图片
C语言文件操作(下)_第2张图片
功能:根据文件指针的位置和偏移量来定位文件指针
参数一:流,从而控制要进行操作的文件
参数二:offset,偏移量,以字节为单位,正数表示正向偏移,负数表示负向
参数三:初始位置,有三种:文件起始点(SEEK_SET)、当下点(SEEK_CUR)、文件末尾(SEEK_END),这三个位置点可以分别被0、1、2代替
返回值:操作成功返回0,操作失败(比如offset超过文件自身大小)返回非0(有的编译器返回-1)
练习1:在data.txt文件中写下abcdefghi,从当下位置SEEK_CUR偏移找到某个字母

int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	int ch = fgetc(pf);
	printf("%c\n", ch);//a

	ch = fgetc(pf);
	printf("%c\n", ch);//b

	ch = fgetc(pf);
	printf("%c\n", ch);//c

	fseek(pf, -3, SEEK_CUR);//SEEK-CUR可用1替代
	ch = fgetc(pf);
	printf("%c\n", ch);//a

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

操作台显示结果:
C语言文件操作(下)_第3张图片
练习2:找从data.txt文件末尾位置SEEK_END向前偏移5个得到的字符

data.txt文件中的内容:
C语言文件操作(下)_第4张图片

int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fseek(pf, -5, SEEK_END);
	int ch = fgetc(pf);
	printf("%c", ch);

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

得到字符e:
C语言文件操作(下)_第5张图片

2. ftell:计算相对于起始位置的偏移量

C语言文件操作(下)_第6张图片
功能:返回光标在文件中相对于起始位置的偏移量
返回值:成功调用函数时,返回偏移量;调用失败,返回-1L
练习:读取三个字符后返回指针的偏移量(data.txt文件中写着abcdefghi)

int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	int ch = fgetc(pf);
	printf("%c\n", ch);

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

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

	int pos = ftell(pf);
	printf("%d\n", pos);

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

控制台显示结果:
C语言文件操作(下)_第7张图片

3.rewind:将指针置于文件起点

C语言文件操作(下)_第8张图片
功能:让指针直接回到文件起始位置
让指针直接回到起始位置的另一种方法:用fseek函数,得到从起始点偏移量为0的位置。具体写法:fseek(pf,0,SEEK-SET)
练习:让光标回到文件起点并打印出该光标后的字符

int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	int ch = fgetc(pf);
	printf("%c\n", ch);//a

	ch = fgetc(pf);
	printf("%c\n", ch);//b

	ch = fgetc(pf);
	printf("%c\n", ch);//c

	rewind(pf);
	ch = fgetc(pf);
	printf("%c\n", ch);//a

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

控制台显示结果:
C语言文件操作(下)_第9张图片

七.文件读取失败的原因判定

1.文本文件读取失败时,一般返回EOF或NULL;二进制文件读取失败时,返回值小于实际要读的个数。但这些不能说明具体因为什么失败
2.一般读取失败的原因有两个,一是读取过程中遇到错误,用ferror函数检测;二是遇到文件末尾,用feof检测

1.ferror函数与feof函数

(1)ferror函数
C语言文件操作(下)_第10张图片
返回值:无错误时返回0;有错误时返回非零值
(2)feof函数
C语言文件操作(下)_第11张图片
返回值:未到文件末尾返回0;到文件末尾返回非零值

2.文件读取失败原因的判断方法

通过两次判断,一次是ferror,一次是feof:
if (ferror(fp)):无错误返回0,有错误返回非零,进入if语句说明有错误。
else if (feof(fp)):未到末尾返回0,到末尾返回非零,进入if语句说明遇到文件末尾。
(1)文本文件的例子:

int main(void)
{
	int c; 
	FILE* fp = fopen("test.txt", "r");
	if (fp==NULL)
	{
		perror("File opening failed");
		return 1;
	}
	//fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
	while ((c = fgetc(fp)) != EOF) 
	{
		putchar(c);
	}
	//判断是什么原因结束的
	if (ferror(fp))//无错误返回0,有错误返回非零
		puts("I/O error when reading");//进入if语句说明有错误
	else if (feof(fp))//未到末尾 返回0,到末尾返回非零
		puts("End of file reached successfully");//进入if语句说明到末尾
	fclose(fp);
	fp = NULL;
}

(2)二进制文件的例子

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);
	fp = NULL;
	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 //读取的个数不等于实际个数,失败,判断失败原因
	{
		if (ferror(fp))//进入if语句说明遇到读取错误
		{
			perror("Error reading test.bin");
		}
		else if (feof(fp))//进入if语句说明遇到文件末尾
			printf("Error reading test.bin: unexpected end of file\n");
	}
	fclose(fp);
	fp = NULL;
}

八.文件缓冲区

1.缓冲文件系统与文件缓冲区

“缓冲文件系统”是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上。提高电脑工作效率。
C语言文件操作(下)_第12张图片

2.强制让数据存入硬盘的方法:

正常情况是只有数据放满缓冲区后才能放入硬盘,但以下两种方法也可以将数据强制放入硬盘。
法1:刷新文件缓冲区:用fflush函数,参数为pf(流)
法2:关闭文件
例:证明不是因为fclose使数据存入文件(硬盘),而是fflush刷新使得数据从输入缓冲区到文件(硬盘)中:

先在当前程序的路径下创建一个data.txt文件
C语言文件操作(下)_第13张图片
代码实现

#include
int main()
{
	FILE* pf = fopen("data.txt", "w");
	fputs("abcde", pf);
	printf("睡眠10秒,已经写数据了,但打开文件后看不到内容\n");
	Sleep(10000);
	printf("刷新缓冲区\n");
	fflush(pf);
	printf("再睡眠10秒,打开文件后可以看到内容了\n");
	Sleep(10000);
	fclose(pf);
	pf = NULL;
}

运行过程:
第一次打开文件:
C语言文件操作(下)_第14张图片
C语言文件操作(下)_第15张图片
第二次打开文件:
C语言文件操作(下)_第16张图片

C语言文件操作(下)_第17张图片
成功运行结束:
C语言文件操作(下)_第18张图片

3.关于数据丢失

如果不关闭文件或刷新缓冲区,则放入缓冲区的数据可能会丢失。

你可能感兴趣的:(c语言,开发语言)