C语言之文件操作(2)

时间:2022-07-03 01:24:48


一、文件的随机读写

1.fseek函数

1.1函数原型

C语言之文件操作(2)

1.2函数功能

通过文件指针当前指向的位置和相对于该位置的偏移量重新设置文件指针所指向文件的位置

1.3函数参数解释

C语言之文件操作(2)

 第一个参数,stream,指向我们要操作文件的文件指针;

第二个参数offset,相对于文件指针所指向的位置的偏移量,可以是正数,也可以是负数

 第三个参数origin,文件指针所指向的位置,这里的位置可以是文件头,也可以是文件尾,也可以是当前指向的位置,origin是int类型,它只有0,1,2三个可能选值

0对应SEEK_SET,表示文件头,

1对应SEEK_CUR,表示文件当前位置

2对应SEEK_END,表示文件尾

C语言之文件操作(2)


返回值:函数执行成功返回0,失败返回!0,并设置error错误代码

需要注意的时,当偏移量会使文件指针指向文件开头的前面或者文件末尾的后面时,也会返回0,因此返回0,并不代表操作完全正确

1.4为什么要使用fseek函数

通过fseek函数,在操作文件时,可以做到指哪打哪,而不是像顺序读写一样挨个读写

1.5函数使用

源代码如下,请君自取

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	FILE* pf = fopen("text.dat", "w");
  //以只写的方式打开文件text.dat
	if (pf == NULL)//判段打开是否成功
	{
  perror("fopen");//失败则报错,并且返回
  return 1;
	}
	char arr[30] = { 0 };
	fputs("abcdef", pf);//向文件写入abcdef
	fclose(pf);
	pf = fopen("text.dat", "r");
  //只读打开刚才的文件
  if (pf == NULL)//判段打开是否成功
	{
  perror("fopen");//失败则报错,并且返回
  return 1;
	}
	char ch;
	fseek(pf, 1, 0);//使pf指向相对于文件头(a),偏移量为1的位置(b)
	ch = fgetc(pf);//读取pf指向的第一个字符(b),并使pf指向下一个字符(c)
	printf("%c\n", ch);//打印
	fseek(pf, 1, 1);//使pf指向相对于文件当前位置(c),偏移量为1的位置(d)
	ch = fgetc(pf);//读取pf指向的第一个字符(d),并使pf指向下一个字符(e)
	printf("%c\n", ch);//打印
	fseek(pf, -1, 2);//使pf指向相对于文件末(\0),偏移量为-1的位置(f)
	ch = fgetc(pf);//读取pf指向的第一个字符(f),并使pf指向下一个字符(e)
	printf("%c\n", ch);//打印
	fclose(pf);//关闭文件
	pf = NULL;//置空
}

执行结果

C语言之文件操作(2)

2.ftell

2.1函数原型

C语言之文件操作(2)

2.2函数功能

返回文件指针相对于文件头的偏移量字节数

2.3函数参数解释

stream,指向目标文件的文件指针,

返回值:执行成功返回文件指针相对于文件头的偏移量字节数,执行失败返回-1

2.4函数使用

源代码如下,请君自取

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	FILE* pf = fopen("text.dat", "w");
  //以只写的方式打开文件text.dat
	if (pf == NULL)//判段打开是否成功
	{
  perror("fopen");//失败则报错,并且返回
  return 1;
	}
	fputs("abcdef", pf);//向文件写入abcdef
	fclose(pf);
	pf = fopen("text.dat", "r");
  //只读打开刚才的文件
  if (pf == NULL)//判段打开是否成功
	{
  perror("fopen");//失败则报错,并且返回
  return 1;
	}
	fseek(pf, 3, 0);//让pf指向距离文件头(a)偏移量为3的位置(d)
	long sz=ftell(pf);
	printf("%ld\n", sz);//返回偏移量(3)
  }

执行结果

C语言之文件操作(2)

3.rewind

3.1函数原型

C语言之文件操作(2)

3.2函数功能

让文件指针的位置回到文件的起始位置

3.3函数参数解释

stream,表示函数指针指向的文件

3.4函数使用

源代码如下,请君自取

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	FILE* pf = fopen("text.dat", "w");
  //以只写的方式打开文件text.dat
	if (pf == NULL)//判段打开是否成功
	{
  perror("fopen");//失败则报错,并且返回
  return 1;
	}
	fputs("abcdef", pf);//向文件写入abcdef
	fclose(pf);
	pf = fopen("text.dat", "r");
  //只读打开刚才的文件
  if (pf == NULL)//判段打开是否成功
	{
  perror("fopen");//失败则报错,并且返回
  return 1;
	}
	fseek(pf, 2, 0);//使pf指向距离文件头(a)偏移量为2位置(c)
	char ch=fgetc(pf);//读取pf指向的第一个字符(c)
	printf("%c\n", ch);//打印
	rewind(pf);//使Pf重新指向文件头位置(a)
	ch = fgetc(pf);//读取pf指向的第一个字符(c)
	printf("%c\n", ch);//打印
  }

执行结果

C语言之文件操作(2)

二、文本文件与二进制文件

1.数据在内存中的存储形式

字符在内存中以ASCIL值的形式存储,数值型数据既可以ASCIL码值的形式存储,也可以使用二进制的形式存储

2.什么是文本文件和二级制文件

首先要明确一点,文本文件和二进制文件是在外存中文件数据的不同存储形式

将内存中的二进制数据不加转换的存储到外存中的文件中,这个外存文件就被称为二进制文件,如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件。

举例:十进制整数10000在内存中的二进制存储

0000000000000000 0010 0111 0001 0000,将其化解为16进制并且在小端存储的情况下,在内存中的存储形式为 10 27 00 00

将其存入外存中的形式:

ASCIL存储形式(需要转换):如果将10000当作字符,那么存储的是字符的ASCIL码值,1的ASCIL码值为49,0为48,一共五个字符

00110001 00110000 00110000 00110000 00110000 (0x30 30 30 30 31)

二进制存储形式(不加转换)

0000000000000000 0010 0111 0001 0000(0x10 27 00 00)

测试代码:

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	int a = 10000;//在内存创建变量a
	FILE* pf = fopen("text1.txt", "wb");//为了输出数据,打开一个二进制文件
	fwrite(&a, 4, 1, pf);//将变量a以二进制的形式写入到二进制文件text1.txt中
	fclose(pf);
	pf = NULL;

}

C语言之文件操作(2)

调试后可以看到a在内存中的存储确实是10 27 00 00,即二进制形式

执行程序后

C语言之文件操作(2)

确实打开了一个二进制文件并且写入了内容,但是我们看不懂

我们选择源文件,添加现有项,选中text1.txt,将其添加进来,选择打开方式,以二进制编译器的方式打开,得到在text1.txt中,数据的内容

C语言之文件操作(2)

C语言之文件操作(2)

文件text1.txt中数据的存储和在内存中数据的存储都是二进制形式,因此,tetx1.txt确实是二进制文件

三、文件读取结束的判定

1.文本文件读取结束判定

1.1fgetc函数返回值分析

读取失败,返回EOF(-1),读取失败又分为两种情况

1.遇到文件末尾,返回EOF,并设置一个状态,表示遇到了文件末尾,这个状态可以用feof函数检测

2.遇到错误,返回EOF,并设置一个状态,表示遇到了错误,这个状态可以用ferror函数检测

1.2fgets函数返回值分析

读取失败,返回空指针

1.3小结

文本文件结束判断,判断返回值是否为EOF(fgetc)或者NULL(fgets)

2.二级制文件读取结束判定

2.1fread函数返回值分析

fread用于二进制文件的读取,它的返回值是读取到的数据的个数

当返回值小于我们实际要读取的数据个数时,说明读取结束

2.2小结

二进制文件读取结束判断,返回值是否小于实际读取个数

3.feof函数和ferror函数使用分析

feof,当文件读取结束后(或者说是读取失败),判断文件是否因为遇到文件末尾导致的读取结束

ferror,当文件读取结束后(或者说是读取失败),判断文件是否因为遇到错误导致的读取结束

3.1文本文件feof,ferror使用实例

代码如下,请君自取

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	char* arr ="abcdef";
	FILE* pf = fopen("text2.txt", "w");
  if (pf == NULL)//判段打开是否成功
	{
  perror("fopen");//失败则报错,并且返回
  return 1;
	}
	fwrite(arr,1,6, pf);
	fclose(pf);
	pf = fopen("text2.txt", "r");
	int c ;
	while ((c = fgetc(pf)) != EOF)
	{
  putchar(c);
	}//跳出循坏后,表示文件读取结束
  //判断文件读取结束具体原因
	if (ferror(pf))
	{
  printf("因为遇到错误而导致文件读取结束\n");
	}
	else if (feof(pf))
	{
  printf("因为遇到文件末尾而导致文件读取结束\n");
	}
	fclose(pf);
	pf = NULL;
}

执行结果

C语言之文件操作(2)

3.2二进制文件feof,ferror使用实例

代码如下,请君自取

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
int main()
{
	char* arr = "abcdef";
	FILE* pf = fopen("text3.txt", "wb");
  //为了输出数据,打开一个二进制文件
	if (pf == NULL)//判段打开是否成功
	{
  perror("fopen");//失败则报错,并且返回
  return 1;
	}
	fwrite(arr, 1, 6, pf);
  //二进制输出
	fclose(pf);
	pf = fopen("text3.txt", "rb");
  //为了输入数据,打开一个二进制文件
	char arr2[6] = { 0 };
	size_t ret = fread(arr2, 1, 6, pf);
  //接收二进制输入的返回值(读取到的个数),实际要读取的个数为6
	if (ret == 6)
	{
  puts("正常结束\n");
  for (int i = 0; i < 6; i++)
  {
  	printf("%c ", arr2[i]);
  }
	}
	else
	{
  if (ferror(pf))
  {
  	printf("因为遇到错误而导致文件读取结束\n");
  }
  else if (feof(pf))
  {
  	printf("因为遇到文件末尾而导致文件读取结束\n");
  }
	}
	fclose(pf);
	pf = NULL;
}

执行结果

C语言之文件操作(2)