(C语言)文件操作(万字超详解)

目录

一:文件的意义(为什么使用文件)

二:什么是文件?

存放在磁盘(硬件)上的文件就是文件。

1:在程序设计中,我们⼀般谈的文件有两种:程序文件、数据文件(从文件功能的角度来分类的)。

2.文件名:

3.二进制文件和文本文件

三:文件的打开与关闭

1.文件指针

2.为什么会有文件指针?

3.流和标准流

流:

标准流:

4.文件的打开与关闭

fopen:

fclose:

四:文件的读写

(一)顺序读写

1.fgetc:

2.fgets:

 3.fputc:

4.fputs

 5.scanf/sscanf/fscanf

(1)scanf:

(2)sscanf:  

 sscanf的优点:

(3)fscanf:

6:printf/sprintf/fprintf

(1)printf

(2)sprintf:

(3) fprintf:

7.fread和fwrite

(1)fread:

(2)fwrite:

 (二):文件的随机读写

1.什么是文件的随机读写?

2.文件随机读写函数介绍

1.fseek:

 2.ftell

3.rewind

 五:文件读取结束的判定

1.被错误使⽤的 feof

 2. ⼆进制文件的读取结束判断

文本文件举例:

二进制文件举例:

 六.文件缓冲区

这⾥可以得出⼀个结论: 因为有缓冲区的存在,C语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文 件。 如果不做,可能导致读写文件的问题。

至此,C语言文件操作内容基本讲解完毕。撒花。


一:文件的意义(为什么使用文件)

当我们写程序时,会对程序进行输入和输出数据,但是当我们退出程序时,程序中的数据自然不复存在了,等我们下次再运行程序时,又需要重新输入程序,这样会影响我们写程序的效率。

因此,我们可以使用文件把数据直接保存再电脑的硬盘上,做到了数据的持久化。

二:什么是文件?

存放在磁盘(硬件)上的文件就是文件。

1:在程序设计中,我们⼀般谈的文件有两种:程序文件、数据文件(从文件功能的角度来分类的)。

程序文件:程序文件包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows 环境后缀为.exe)。

数据文件:文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件,用来提供数据或者存储数据。

如:用函数操作文件(打开、输出等等操作),该文件就是数据文件。并且本博客内容讨论的都是数据文件。

2.文件名:

文件名就是文件的一个名字,一个文件要有一个唯一的文件标识,以便用户识别和引用。

文件名包括三个部分:文件路径+文件名主干+文件后缀

如: c:\code\test.txt

c:\code\:表示文件路径      test:表示文件名主干      .txt:表示文件后缀

3.二进制文件和文本文件

根据数据的组织形式,数据文件被称为文本文件或者⼆进制文件。

二进制文件:二进制文件就是把内存中的数据按其在内存中存储的形式原样存储在磁盘上。

如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的⽂件就是文本文件

数据在内存中如何存储呢?

字符⼀律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式储。 如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符⼀个字节),而⼆进制形式输出,则在磁盘上只占4个字节。

6645d8ef2bf742f8a2e4c16a1e5e1df7.png

代码示例:

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int a = 100;
	FILE* pa = fopen("text.txt", "wb");
	fwrite(&a, 4, 1, pa);
	fclose(pa);
	pa == NULL;

	return 0;
}

此时我们打开文件看看是否是以二进制存储的(vs2022)

步骤1:添加源文件,选择现有项

9e1307b65a2f4a4cbd30cbb82f47fce0.png

步骤2:添加text文件

36c41527dcfa4e5c8f008ce777c788d2.png

步骤3:右击文件,选择打开方式——二进制编译器

d10aa10f89e64839933dc930c0cad9ac.png

此时,就可以看到数据在文件中以二进制形式存储

a6f0d18ed2bc4207a7471520dc6a7e84.png

三:文件的打开与关闭

1.文件指针

文件类型指针 简称“文件指针”。

2.为什么会有文件指针?

每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是由系统声明的,取名FILE

struct _iobuf {
    char *_ptr;
    int  _cnt;
    char *_base;
    int  _flag;
    int  _file;
    int  _charbuf;
    int  _bufsiz;
    char *_tmpfname;
   };
typedef struct _iobuf FILE;

 不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。

每当我们打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,该变量就指向了文件信息区,通过该指针就可以找到文件。使用者不必关心细节。

所以我们需要创造一个文件指针变量来接收打开文件后返回的变量,该指针变量就可以访问该文件。

FILE*pf;

总结:定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联的文件。

3.流和标准流

流:

我们程序的数据需要输出到各种外部设备,也需要从外部设备获取数据,不同的外部设备的输入输出 操作各不相同,为了方便程序员对各种设备进行方便的操作,我们抽象出了流的概念,我们可以把流 想象成流淌着字符的河。 C程序针对文件、画面、键盘等的数据输⼊输出操作都是通过流操作的。⼀般情况下,我们要想向流里写数据,或者从流中读取数据,都是要打开流,然后操作。从概念上看,c语言程序处理的是流而不是直接处理文件。

标准流:

流是一种抽象化的数据概念,并不是实际存在的,我们在写c程序的时候都会在开头加上一句

#include<stdio.h>

这里的stdio.h头文件叫做标准输入输出头文件,stdio指的是“standard input&output”(标准输入输出)。

stdin——标准输入流stdin绑定键盘,将键盘视为存储设备上的普通文件,我们在键盘上输入的字符数据都会被存放在这个流中,这些字符数据被他视为从文件中提取的数据,键盘是数据的来源。我们c语言中常用的scanf函数就是从stdin流中提取数据存入到我们指定的变量从而达到预期目标。

标准输出流stdout是类似的不过stdout绑定的是我们的电脑显示器,它将显示器视为存储设备上的一个普通文件。显示器是这种标准输出函数的主要目标,是数据复制后的去向,在我们使用printf之类的函数时,他们会将指定的字符串和变量数据输入到stdout流中,进而显示在显示器上。

4.文件的打开与关闭

文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。

在编写程序的时候,在打开文件的同时,都会返回⼀个FILE*的指针变量指向该文件,也相当于建立了 指针和文件的关系。 ANSIIC规定使用fopen 函数来打开文件, fclose 来关闭文件。 FILE * fopen ( const char * filename, const char * mode)

fopen:

函数原型为: FILE *fopen(const char *filename, const char *mode);

其功能是使用给定的模式 mode 打开 filename 所指向的文件。文件顺利打开后,指向该流的文件指针就会被返回。如果文件打开失败则返回 NULL,并把错误代码存在 error 中。该函数位于C 标准库<stdio.h>中。

fclose:

函数原型:int fclose( FILE *fp );

返回值:如果流成功关闭,fclose 返回 0,否则返回EOF(-1)。(如果流为NULL,而且程序可以继续执行,fclose设定error number给EINVAL,并返回EOF。)

下面是文件的打开方式:

"r"(只读) 为输入打开一个文本文件 

"w"(只写) 为输出打开一个文本文件 

"a"(追加) 向文件文件尾添加数据

"rb"(只读) 为输入打开一个二进制文件

"wb"(只写) 为输出打开一个二进制文件

"r+"(读写) 为读写打开一个文本文件

"w+"(读写) 为读写建立一个新的文本文件

"a+"(读写) 为读写打开一个文本文件

"rb+"(读写) 为读写打开一个二进制文件

"wb+"(读写) 为读写建立一个新的二进制文件

"ab+"(读写) 为读写打开一个二进制文件

注1:在使用"w" 、"a"、"wb"、"ab"、"w+"、"a+"、“wb+”、"ab+"这些打开方式时,若指定文件不存在,则会自动创建指定文件。其他方式遇到文件不存在时则会出错。

注2:当时用"w"、"wb"、"w+"、"wb+"这些打开方式时会清除文件原本存储的数据

代码示例:

#include<stdio.h>
int main()
{
	FILE* pa = fopen("text.txt", "w");//为输出打开一个文本文件
	if (pa == NULL)//判断是否打开成功
	{
		perror("fopen");
		return 1;
	
	fclose(pa);//关闭文件
	pa == NULL;//将pa置为空指针,防止野指针

	return 0;
}

四:文件的读写

文件的读写我们有两种读写方式:顺序读写和随机读写。

(一)顺序读写

对于顺序读写我们会常用到以下函数:

功能函数名适用于
字符输入函数fgetc所有输入流
字符输出函数fputc所有输出流
文本行输入函数fgets所有输入流
文本行输出函数fputs所有输出流
格式化输入函数fscanf所有输入流
格式化输出函数fprintf所有输出流
二进制输入fread文件
二进制输出fwrite文件

下面来介绍这些函数。

1.fgetc:

函数原型:int fgetc(FILE *stream);

意为从文件指针stream指向的文件中读取一个字符,该字符的ASCII值作为函数的返回值,读取一个字节后光标向后移一个字节,若返回值为EOF,说明文件结束,EOF是文件结束标志,值为-1。

代码示例:

int main()
{
	FILE* pb = fopen("text.txt", "r");//为输入打开一个文本文件
	if (pb == EOF)//判断是否打开成功
	{
		perror("fopen");
		return 1;
	}
	int ch = 0;
	while((ch=fgetc(pb)) != EOF)判断是否成功输入数据
	{
		printf("%c", ch);//成功读取则将外部文件中的数据输入到程序中
	}
	printf("\n");
	fclose(pb);//关闭文件
    pb==NULL;//将pb置为空指针
	return 0;

2.fgets:

fgets函数功能为从指定的流中读取数据,每次读取一行。

其函数原型::char *fgets(char *str, int n, FILE *stream);

应用说明:

从指定的流 stream 读取一行,并把它存储在 str 所指向的字符串内。当读取 (n-1) 个字符时,或者读取到换行符时,或者到达文件末尾时,它会停止,具体视情况而定。

如果文件中的该行,不足n-1个字符,则读完该行就结束。如若该行(包括最后一个换行符)的字符数超过n-1,则fgets只返回一个不完整的行。

返回值:

如果成功,该函数返回str的头指针。如果到达文件末尾或者没有读取到任何字符,str 的内容保持不变,并返回一个空指针。如果发生错误,返回一个空指针。

代码示例:

int main()
{
	FILE* pc = fopen("text.txt", "r");//为了输入数据打开文件
	if (pc == NULL)//判断是否打开成功
	{
		perror("fopen");
		return 1;
	}
	char arr[30] = { 0 };//创造数组
	fgets(arr, 26 + 1, pc);//将读取到的字符串串存储到arr指向的字符串内,如果外部文件中有两行字符串,只需再读取一次
	puts(arr);             //打印字符串
	fclose(pc);//关闭文件
	pc = NULL;//置为空指针

	return 0;

 3.fputc:

函数功能: 将字符c写到文件指针fp所指向的文件的当前写指针的位置。

函数原型:int fputc (char c, File *fp),fp为文件指针,c为输入的字符量。

虽然函数被定义为整型数,但仅用其低八位。

返回值:在正常调用情况下,函数返回写入文件的字符的ASCII码值,出错时,返回EOF(-1)。当正确写入一个字符或一个字节的数据后,文件内部写指针会自动后移一个字节的位置。

int main()
{
	FILE* pa = fopen("text.txt", "w");//打开文件,打开方式为输出数据w
	if (pa == NULL)//判断是否打开成功
	{
		perror("fopen");
		return 1;
	}
	for (int i = 0; i < 26; i++)//成功打开后则把程序中的数据输出到外部文件中
	{
		int ret=fputc('a' + i, pa);
		printf("%c",ret);
	}
	if (fclose(pa) == EOF)//判断是否关闭文件成功
	{
		perror("fclose");
		return 1;
	}
	pa == NULL;//将pa置为空指针,防止野指针

	return 0;

4.fputs

功能是向指定的文件写入一个字符串(不自动写入字符串结束标记符‘\0’)。成功写入一个字符串后,文件的位置指针会自动后移。

函数原型:int fputs(const char *str, FILE *stream);

返回值:该函数返回一个非负值,如果发生错误则返回 EOF(-1)。

(1)str:这是一个数组,包含了要写入的以空字符终止的字符序列。

(2)stream:指向 FILE 对象的指针,该 FILE 对象标识了要被写入字符串的流。

代码实例:

int main()
{
	FILE* pd = fopen("text.txt", "w");//为了将程序中的数据输入到外部文件,打开文件
	if (pd == NULL)//判断
	{
		perror("fopen");
		return 1;
	}
	char arr[20] = "abcdefghijklmn";//创建数组
	if ((fputs(arr, pd)) == EOF)//判断是否输入成功
	{
		perror("fputs");
		return 1;
 	}
	if (fputs("hello", pd) == EOF)//判断是否输入成功
	{
		perror("fputs2");
		return 1;
	}
	if (fclose(pd) == EOF)//判断是否关闭成功
	{
		perror("fclose");
		return 1;
	}
	pd = NULL;
    return 0;
}

运行结果:

 6ac8aa8cde9e4381b16021e054d5b686.png

 5.scanf/sscanf/fscanf

(1)scanf:

函数原型:int scanf(const char * restrict format,...);

函数 scanf() 是从标准输入流stdin (标准输入设备,一般指向键盘)中读内容的通用子程序,可以说明的格式读入多个字符,并保存在对应地址的变量中。

函数的第一个参数是格式字符串,它指定了输入的格式,并按照格式说明符解析输入对应位置的信息并存储于可变参数列表中对应的指针所指位置。每一个指针要求非空,并且与字符串中的格式符一一顺次对应。

代码实例:

int main()
{
	int i = 0;
	//从标准输入流(键盘)读取数据
	scanf("%d", &i);
	return 0;
}

(2)sscanf:  

C语言中,sscanf函数是一个的字符串格式化函数,用于从字符串中按照指定的格式解析数据,存储在对应的变量中。

sscanf与scanf类似,都是用于输入的,只是后者以键盘(stdin)为输入源,而sscanf是从字符串中提取数据。

函数原型:int sscanf(  const char *str,     const char *format, ...   );

str:要解析的字符串      format:格式字符串      ...:可变参数列表,用于接收解析后的数据

返回值:函数将返回成功赋值的字段个数,失败返回0 ,否则返回格式化的参数个数。

代码示例:

int main()
{
	char arr[] = "abcdefg";//创建字符串arr
	char arr1[10] = { 0 };//创建字符串arr1
	sscanf(arr, "%s", arr1);//从字符串arr中读取数据放入arr1中
	printf("%s\n", arr1);//打印出来
	int n = 0;
	sscanf("abcde 123", "%s %d", arr1,&n);
	printf("%s %d", arr1,n);

	return 0;
}

运行结果:

fdce9cc9e5f94938b1fc20691a6a0607.png

 sscanf的优点:

  • sscanf函数可以根据格式字符串的规则解析不同类型的数据,具有很高的灵活性。
  • 在使用sscanf函数时,要确保格式字符串与要解析的数据格式匹配,否则可能会导致解析错误或未定义的行为
  • 需要注意的是,sscanf函数只会从字符串中解析数据,不会对字符串进行修改。

(3)fscanf:

函数原型: int fscanf(FILE * stream, const char * format, ...);

stream:要读取的文件指针,可以是标准输入流stdin、文件指针或者其他已经打开的文件流。

format:格式控制字符串,指定了要读取的数据的格式和顺序。

...:可变参数列表,用于接收读取的数据。

fscanf其功能为根据数据格式(format),从输入流(stream)中读入数据,存储到...中,遇到空格和换行时结束,这与fgets有区别,fgets遇到空格不结束。

代码示例:

int main()
{
	FILE* pb = fopen("text.txt", "r");//打开文件
	if (pb == NULL)                   //判断是否打开成功
	{
		perror("fopen1");
		return 1;
	}
	char b = 0; //创建字符变量b
	char arr[10] = { 0 };//创建字符串arr
	fscanf(pb, "%c\n%s",&b, arr);      //从文件流中读取数据格式化后分别放到b和arr中
	printf("%c\n", b);                   //打印出来
	printf("%s", arr);
	fclose(pb);                        //关闭文件
	pb = NULL;                         //置为空指针

	return 0;
}

运行结果:

ac88f8d041034f5ab3eea49d51a3b5de.png

6:printf/sprintf/fprintf

(1)printf

printf是指格式化输出函数,主要功能是向标准输出设备按规定格式输出信息。

头文件 <stdio.h>

函数声明:int printf( const char *format, ... );

format -- 是格式控制字符串,包含了两种类型的对象:普通字符和转换说明 。在输出时,普通字符将原样不动地复制到标准输出,转换说明并不直接输出而是用于控制 printf 中参数的转换和打印。每个转换说明都由一个百分号字符(%)开始,以转换说明结束,从而说明输出数据的类型、宽度、精度等 。

代码示例:

#include<stdio.h>//头文件
int main()
{
    char arr[10]="abc"
	printf("你好,我是%s",a);
	return 0;
}

(2)sprintf:

sprintf指的是字符串格式化命令,函数声明为 int sprintf(char *str, char *format ,...);

主要功能是把格式化的数据写入某个字符串中,即发送格式化输出到 str 所指向的字符串

sprintf跟printf在用法上几乎一样,只是打印的目的地不同而已,前者打印到字符串中,后者则直接在命令行上输出。

返回值:如果成功,则返回写入的字符总数,不包括字符串追加在字符串末尾的空字符。如果失败,则返回一个负数。

代码示例:

int main()
{
	char arr[] = "abcdef";//创建字符串arr
	int num = 10;//创建变量num
	char arr1[10] = { 0 };//创建字符串arr1
	sprintf(arr1, "%s %d", arr,num);//把格式化的数据存放到arr1中
	puts(arr1);//打印arr1

	return 0;
}

运行结果:

baf9124a5ab84ab39af0768a10a58cf9.png

(3) fprintf:

fprintf是一个格式化库函数,位于头文件<stdio>;中,其作用是格式化输出到一个流文件中;

函数原型:int fprintf (FILE* stream, const char*format,...);

功能:fprintf()函数根据指定的格式(format),向输出流(比如文件流)写入数据...。 

返回值:

  1. 写文件成功,则返回写入的总字符数;
  2. 写文件失败,则返回负值。

代码示例:

int main()
{
	FILE* pa = fopen("text.txt", "w");//以写的方式打开文件
	if (pa == NULL)//判断文件是否打开成功
	{
		perror("fopen");
		return 1;
	}
	char arr[] = "abcdef";//创建字符串arr
	int a = 10;//创建变量a
	fprintf(pa, "%s %d", arr, a);//把格式化数据输出到文件中
	fclose(pa);//关闭文件
	pa == NULL;//置为空指针
	return 0;
}

运行结果:

d7a1bab4671d48a5bd55a49f6640af25.png

说完了顺序读写,继续说一下随机读写。 

7.fread和fwrite

(1)fread:

fgets有局限性,每次最多只能从文件中读取一行内容,因为 fgets遇到换行符就结束读取。如果希望读取多行内容,需要使用 fread函数;相应地写入函数为 fwrite。
fread 函数用来从指定文件中读取块数据。所谓块数据,也就是若干个字节的数据,可以是一个字符,可以是一个字符串,可以是多行数据,并没有什么限制。

函数原型:size_t fwrite ( void * ptr, size_t size, size_t count, FILE *fp );

函数功能:从给定输入流stream读取最多count个对象存储到指针ptr指向的数组中,每个对象size个字节,该函数以二进制形式对文件进行操作,不局限于文本文件。

返回值

返回成功读取的对象个数,若出现错误或到达文件末尾,则可能小于count。

*  若size或count为零,则fread返回零且不进行其他动作。

*  fread不区分文件尾和错误,因此调用者必须用feof和ferror才能判断发生了什么

(2)fwrite:

函数原型:size_t fwrite(const void *ptr, size_t size, size_t num, FILE *stream);

函数功能:把ptr指向的数组中的数据存储numsize字节的数据到输出流stream中,该函数以二进制形式对文件进行操作,不局限于文本文件。

返回值:如果成功,该函数返回一个 size_t 对象,表示元素的总数,该对象是一个整型数据类型。如果该数字与num参数不同,则会显示一个错误。 

代码示例:

#include<stdio.h>
int main()
{
	FILE* pa = fopen("text.txt", "wb");//以输出二进制数据打开文件
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	fwrite(arr, sizeof(arr), 5, pa);//输入5个整型放在文件流中
	fclose(pa);//关闭文件
	pa == NULL;
	FILE* pb = fopen("text.txt", "rb");//以读取二进制数据打开文件
	int arr1[10] = { 0 };
	fread(arr1, 4, 3, pb);//从文件中读取三个整形存储到arr1中
	for (int i = 0; i < 10; i++)//输入
	{
		printf("%d", arr1[i]);
	}
	fclose(pb);
	pb == NULL;

	return 0;
}

运行结果:

54075f6811ef4ce688830c34ef7d488a.png

 (二):文件的随机读写

1.什么是文件的随机读写?

我们使用fopen打开一个文件可以得到一个文件指针,这个文件指针也会被用于读写文件的时候。我们在读取一个文件的时候,文件指针指向下一个我们要读取的字符(一开始指向第一个字符),每当我们调用一次读取函数时,如 fgetc/fgets,这个文件指针就会向后移动一个或者多个单位。

文件的随机读写,就是我们可以指定这个文件指针指向的位置,即指向第几个字符,然后从这个字符开始读写。

2.文件随机读写函数介绍

1.fseek:

函数原型:int fseek(FILE *stream, long offset, int fromwhere);

stream:文件指针  

long offset:相对于起始位置的偏移量

fromwhere:起始位置。三选一。

可选值解析

SEEK_CUR

当前文件指针指向的位置

SEEK_END

文件末尾

SEEK_SET

文件起始位置

返回值:成功返回0,失败返回一个非零值。

代码示例:

#include<stdio.h>
int main()
{
	FILE* pa = fopen("text.txt", "w");//以写的方式打开文件
	if (pa == NULL)//判断是否打开文件
	{
		perror("fopen");
		return 1;
	}
	fputs("abcdefgh", pa);//把字符串输出到文件流中
	fseek(pa, 5, SEEK_SET);//把光标移到起始位置向右偏移量为5的位置
	fputs("123", pa);//把字符串123输出到文件流中
	fclose(pa);
	pa == NULL;

	return 0;
}

运行结果:69767f2119994a8d825df8f73fd02458.png

 2.ftell

在随机方式存取文件时,由于文件位置频繁的前后移动,程序不容易确定文件的当前位置,我们可以用ftell解决这个困扰。

ftell函数用于得到文件位置指针当前位置相对于文件首的偏移字节数。

函数原型:long ftell(FILE *stream);

stream:文件指针    

返回值:成功则返回一个偏移量,失败则返回-1。

代码示例:

int main()
{
	FILE* pa = fopen("text.txt", "w");//以写的方式打开文件
	if (pa == NULL)//判断是否打开文件
	{
		perror("fopen");
		return 1;
	}
	fputs("abcdefgh", pa);//把字符串输出到文件流中
	fseek(pa, 5, SEEK_SET);//把光标移到起始位置向右偏移量为5的位置
	int a=ftell(pa);
	printf("%d", a);//打印出5
    fclose(pa);
    pa==NULL;

	return 0;
}

3.rewind

功 能: 将文件内部的位置指针重新指向一个流(数据流/文件)的开头

函数原型:void rewind(FILE *stream);

代码示例

int main()
{
	FILE* pa = fopen("text.txt", "w");//以写的方式打开文件
	if (pa == NULL)//判断是否打开文件
	{
		perror("fopen");
		return 1;
	}
	fputs("abcdefgh", pa);//把字符串输出到文件流中
	fseek(pa, 5, SEEK_SET);//把光标移到起始位置向右偏移量为5的位置
	int a=ftell(pa);
	printf("重置之前偏移量为%d\n", a);
	rewind(pa);//把文件指针重置到文件起始位置
	int b = ftell(pa);
	printf("重置之后偏移量%d", b);
	fclose(pa);
	pa == NULL;

	return 0;
}

运行结果:3418eb302bf14ab4b60bfddf4d29807a.png

 五:文件读取结束的判定

1.被错误使⽤的 feof

牢记:在文件读取过程中,不能⽤feof函数的返回值直接来判断⽂件的是否结束。feof 的作用是:当⽂件读取结束的时候,判断是读取结束的原因是否是:遇到⽂件尾结束。 1. 文本文件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )

例如:

• fgetc 判断是否为 EOF

• fgets 判断返回值是否为 NULL .

 2. ⼆进制文件的读取结束判断

例如: • fread判断返回值是否小于实际要读的个数,若出现错误或到达文件末尾,则可能小于count。

fwrite判断返回值是否等于实际要写入的数据个数。

文本文件举例:

#include <stdio.h>
#include <stdlib.h>
 
int main(void)
{
 int c; // 注意:int,⾮char,要求处理EOF 
 FILE* fp = fopen("test.txt", "r");
 if(!fp) {
 perror("fopen");
 return 1;
 }
 //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);
 fp==NULL;
 return 0;
}

二进制文件举例:

#include<stdio.h>
int main()
{
	FILE* pa = fopen("text.txt", "wb");//以输出二进制数据打开文件
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int ret=fwrite(arr, sizeof(arr), 5, pa);//输入5个整型放在文件流中
	if (ret != 5)//判断是否写入成功
	{
		perror("fwrite");
	}
	fclose(pa);//关闭文件
	pa == NULL;
	FILE* pb = fopen("text.txt", "rb");//以读取二进制数据打开文件
	int arr1[10] = { 0 };
	int rat=fread(arr1, 4, 3, pb);//从文件中读取三个整形存储到arr1中
	if (rat == 3)//判断返回值是否等于size
	{
		printf("返回值等于size\n");
	}
	else//不等于的话判断1.到达文件末尾2.读取出错
	{
		if (feof(pb))
		{
			printf("到达文件末尾");
		}
		else
			perror("fread error");
	}
	for (int i = 0; i < 10; i++)//输入
	{
		printf("%d", arr1[i]);
	}
	fclose(pb);
	pb == NULL;

	return 0;
}

运行结果:feca08e728a848e99c9c6b3a132eae04.png

 六.文件缓冲区

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

#include <stdio.h>
#include <windows.h>
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语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文 件。 如果不做,可能导致读写文件的问题。

至此,C语言文件操作内容基本讲解完毕。撒花。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值