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

这篇具有很好参考价值的文章主要介绍了C语言之文件操作(万字详解)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

个人主页(找往期文章包括但不限于本期文章中不懂的知识点): 我要学编程(ಥ_ಥ)-CSDN博客

目录

前言

文件的打开和关闭 

流和标准流

文件指针

文件的打开和关闭 

文件的顺序读写 

顺序读写函数介绍

fputc的使用 

fgetc的使用 

fputs的使用 

fgets的使用 

fprintf的使用 

fscanf的使用 

对比一组函数(输入与输出) 

sprintf的使用 

sscanf的使用

fwrite的使用 

fread的使用 

文件的随机读写

fseek的使用

ftell的使用 

rewind的使用 

文件读取结束的判定

被错误使用的 feof

文件缓冲区 


前言

为什么要使用文件? 

我们写的程序的数据是存储在电脑的内存中,如果没有文件,程序退出,内存回收,数据就丢失 了,等再次运行程序,是看不到上次程序的数据的,如果要将数据进行持久化的保存,我们就要使用文件。

什么是文件?

磁盘(硬盘)上的文件是文件。 但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件(从文件功能的角度来分类的)。

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

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

本文讨论的是数据文件。 在以前所处理数据的输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显示器上。 其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理的就是磁盘上的文件。

文件名 :一个文件要有一个唯一的文件标识,以便用户识别和引用。 文件名包含3部分:文件路径+文件名主干+文件后缀 例如: c:\code\test.txt 为了方便起见,文件标识常被称为文件名。即一个文件要有一个唯一的文件名。

二进制文件和文本文件 根据数据的组织形式,数据文件被称为文本文件或者二进制文件。 数据在内存中以二进制的形式存储,如果不加转换的输出到外存(与之对应的就是内存)的文件中,就是二进制文件。 如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII码字符的形式存储的文件就是文本文件。 一个数据在文件中是怎么存储的呢? 字符一律以ASCII码形式存储,数值型数据既可以用ASCII码形式存储,也可以使用二进制形式存储。 如整数10000,如果以ASCII码的形式输出到磁盘,则在磁盘中占用5个字节(每个字符一个字节,'1' '0' '0' '0' '0' '0'),而以二进制形式输出,则在磁盘上只占4个字节(一个整数4个字节)。

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

文件的打开和关闭 

流和标准流

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

标准流 那为什么我们使用 scanf函数 从键盘输入数据,使用 printf函数 向屏幕上输出数据,并没有打开流呢? 那是因为C语言程序在启动的时候,默认打开了3个流:

• stdin - 标准输入流,在大多数的环境中从键盘输入,scanf函数就是从标准输入流中读取数据。

• stdout - 标准输出流,大多数的环境中输出至显示器界面,printf函数就是将信息输出到标准输出流中。

• stderr - 标准错误流,大多数环境中输出到显示器界面。

这是默认打开了这三个流,我们使用scanf、printf等函数就可以直接进行输入输出操作的。 stdin、stdout、stderr 三个流的类型是: FILE* ,通常称为文件指针。 C语言中,就是通过 FILE* 的文件指针来维护流的各种操作的。

文件指针

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

VS 编译环境提供的 stdio.h 头文件中有以下的文件类型申明: 

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的指针来维护这个FILE结构的变量,这样使用起来更加方便。

FILE* pf;//⽂件指针变量

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

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

文件的打开和关闭 

文件在进行读写的操作之前应该先打开文件,在使用结束之后应该关闭文件。 在编写程序的时候,打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指针和文件的关系。 ANSI C(标准C) 规定使用 fopen 函数来打开文件, fclose 来关闭文件。函数原型如下:

//打开⽂件
//filename——>文件名
//mode——>方式(以什么样的方式打开这个文件,例如:读,写……)
FILE * fopen ( const char * filename, const char * mode );


//关闭⽂件
//stream——>就是一个文件指针(要被关闭的文件)
int fclose ( FILE * stream );

在介绍这两个函数之前,我们还需要学习一个函数 perror 。

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

这个函数是用来打印错误信息的。这个函数与我们学过的 strerror 函数有关。strerror 函数是把错误码对应的错误信息的地址传给一个char*的指针;如果我们再用 printf 打印的话,就可以知道其内容了,而这个perror就是直接一步到位,打印错误信息。

#include <stdio.h>
#include <string.h>
int main()
{
	char* ret = strerror(1);
	printf("%s\n", ret);
	perror("1");
	return 0;
}

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

当然这里因为没有错误信息,所以它就打印了没有错误。perror 就是会把传进去的参数打印,然后在后面加上冒号与空格。注意的是这个参数传进去的时候要加双引号。

现在就来学习fopen 函数。下面这个表格是文件的打开方式分类:

文件打开方式 含义 如果指定文件不存在 
 "r"(只读) 为了输入数据,打开一个已经存在的文本文件 出错
"w"(只写) 为了输出数据,打开一个文本文件 建立一个新的文件
"a"(追加) 向文本文件末尾添加数据 建立一个新的文件
"rb"(只读) 为了输入数据,打开一个二进制文件 出错
"wb"(只写) 为了输出数据,打开一个二进制文件 建立一个新的文件
"ab"(追加) 向一个二进制文件末尾添加数据 建立一个新的文件
"r+"(读写) 为了读和写,打开一个文本文件 出错
"w+"(读写) 为了读和写,建立一个新的文件 建立一个新的文件
"a+"(读写) 打开一个文件,在文件末尾进行读写 建立一个新的文件
"rb+"(读写) 为了读和写打开一个二进制文件 出错
"wb+"(读 写) 为了读和写,新建一个新的二进制文件 建立一个新的文件
"ab+"(读 写) 打开一个二进制文件,在文件末尾进行读和写 建立一个新的文件
#include <stdio.h>
int main()
{
	//打开文件
	FILE* pf = fopen("data.txt", "r");
	//打开失败
	if (pf == NULL)
	{
		perror("fopen");
		return 1;//打开失败就不需要往后进行了
	}
	//打开成功
	// ……
	//后续操作
	return 0;
}

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

注意如果没有写绝对路径的话,系统就只会在本文件下寻找(就是与这个 .c 文件在同一文件下)。绝对路径就是:D:\c语言\writing-code-for-blogs\test_3_12\test_3_12 这种。当然为了防止有转义字符的出现就需要加上双斜杠。C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

#include <stdio.h>
int main()
{
	//打开文件
	FILE* pf = fopen("data.txt", "w");
	//打开失败
	if (pf == NULL)
	{
		perror("fopen");
		return 1;//打开失败就不需要往后进行了
	}
	//打开成功
	// ……
	//后续操作
	return 0;
}

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

文件的顺序读写 

顺序读写函数介绍

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

上面说的适用于所有输入流一般指适用于标准输入流和其他输入流(如文件输入流);所有输出流一般指适用于标准输出流和其他输出流(如文件输出流)。 现在我们就可以往文件里写入一些字符了。

fputc的使用 

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

fputc 就是把字符输出到流中。 

#include <stdio.h>
int main()
{
	//打开文件
	FILE* pf = fopen("data.txt", "w");
	//打开失败
	if (pf == NULL)
	{
		perror("fopen");
		return 1;//打开失败就不需要往后进行了
	}
	//打开成功,往其中写入一些字符
	fputc('a', pf);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

如果要写多个就得多次调用这个fputc 函数。

#include <stdio.h>
int main()
{
	//打开文件
	FILE* pf = fopen("data.txt", "w");
	//打开失败
	if (pf == NULL)
	{
		perror("fopen");
		return 1;//打开失败就不需要往后进行了
	}
	//打开成功,往其中写入一些字符
	for (int i = 0; i < 26; i++)
	{
		fputc('a' + i, pf);
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

如果我们要打印到屏幕上,就写stdout就可以了。C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

fgetc的使用 

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

这个fgetc就是从所有流中获取字符,也就是读取。

#include <stdio.h>
int main()
{
	//打开文件
	FILE* pf = fopen("data.txt", "r");
	//打开失败
	if (pf == NULL)
	{
		perror("fopen");
		return 1;//打开失败就不需要往后进行了
	}
	//打开成功,读取一些字符
	//读取成功返回字符的ASCll码值,读取失败或者遇到文件末尾返回EOF
	int ret = fgetc(pf);
	printf("%d\n", ret);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

#include <stdio.h>
int main()
{
	//打开文件
	FILE* pf = fopen("data.txt", "r");
	//打开失败
	if (pf == NULL)
	{
		perror("fopen");
		return 1;//打开失败就不需要往后进行了
	}
	//打开成功,读取一些字符
	//读取成功返回字符的ASCll码值,读取失败或者遇到文件末尾返回EOF
	int ret = fgetc(stdin);
	printf("%d\n", ret);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

fputs的使用 

fputs与fputc类似。 

#include <stdio.h>
int main()
{
	//打开文件
	FILE* pf = fopen("data.txt", "w");
	//打开失败
	if (pf == NULL)
	{
		perror("fopen");
		return 1;//打开失败就不需要往后进行了
	}
	//打开成功,输出一些字符
	fputs("hello world", pf);
	fputs("I want learn", pf);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

fgets的使用 

fgets与fgetc就有一些不一样了。

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

fgets是把从stream中读取的num-1个字符放到str这个字符指针中。

#include <stdio.h>
int main()
{
	//打开文件
	FILE* pf = fopen("data.txt", "r");
	//打开失败
	if (pf == NULL)
	{
		perror("fopen");
		return 1;//打开失败就不需要往后进行了
	}
	//打开成功,输出一些字符
	char str[10] = { 0 };
	fgets(str, 8, pf);
	printf("%s\n", str);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

当要读取的字符数超过总字符时,就会只读取总字符数;又或者当读取时遇到'\n'(换行符),也会停止本次读取。

#include <stdio.h>
int main()
{
	//打开文件
	FILE* pf = fopen("data.txt", "r");
	//打开失败
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//打开成功,输入一些字符
	char str[10] = { 0 };
	fgets(str, 8, pf);
	printf("%s", str);
	fgets(str, 8, pf);
	printf("%s", str);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

fprintf的使用 

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

这个fprintf与printf相比,就只多了前面那个FILE* stream参数,我们就可以模拟printf来实现fprintf函数。  

struct S
{
	int i;
	float f;
};
#include <stdio.h>
int main()
{
	//打开文件
	FILE* pf = fopen("data.txt", "w");
	//打开失败
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	struct S s = { 10, 3.14f };
	//打开成功,输入一些字符
	
	//printf("%d %f\n", s.i, s.f);
	fprintf(pf, "%d %f\n", s.i, s.f);

	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

可以从结果来看:fprintf是把s.i , s.f 按照按照%d %f的格式打印到pf中。 

fscanf的使用 

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

这个fscanf与scanf相比,就只多了前面那个FILE* stream参数,我们就可以模拟scanf来实现fscanf函数。 

struct S
{
	int i;
	float f;
};
#include <stdio.h>
int main()
{
	//打开文件
	FILE* pf = fopen("data.txt", "r");
	//打开失败
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	struct S s = { 0 };

	//scanf("%d%f", &(s.i), &(s.f));
	fscanf(pf, "%d%f", &(s.i), &(s.f));

	printf("%d %f\n", s.i, s.f);//看看是否读取成功
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

 可以从结果来看:fscanf是把pf中的数据按照按照%d %f的格式输入到s.i , s.f 中。

对比一组函数(输入与输出) 

scanf ——>从标准输入流读取格式化的数据。

printf  ——>从标准输出流写格式化的数据。

fscanf——>适用于所有输入流的格式化输入函数。

fprintf——>适用于所有输出流的格式化输出函数。

sscanf——>从字符串中读取格式化的数据

sprintf——>将格式化的数据转换成字符串

sprintf的使用 
struct S
{
	int i;
	float f;
};
#include <stdio.h>
int main()
{
	//打开文件
	FILE* pf = fopen("data.txt", "w");
	//打开失败
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	struct S s = { 10 ,3.14f };
	char arr[20] = { 0 };
	//printf("%d %f\n", s.i, s.f);
	sprintf(arr, "%d %f\n", s.i, s.f);
	
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

与printf相比,也只是多了一个字符指针参数。

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

ssprintf也是把s.i, s.f按照%d %f的格式放到arr中。 

sscanf的使用
struct S
{
	int i;
	float f;
};
#include <stdio.h>
int main()
{
	//打开文件
	FILE* pf = fopen("data.txt", "r");
	//打开失败
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	struct S s = { 10 ,3.14f };
	struct S tmp = { 0 };
	char arr[20] = { 0 };

	sprintf(arr, "%d %f\n", s.i, s.f);
	//scanf("%d%f", &(s.i), &(s.f));
	sscanf(arr, "%d%f", &(tmp.i), &(tmp.f));

	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

sscanf是把arr中数据按照%d %f的格式放到&(tmp.i) , &(tmp.f)。

sprintf函数一般是与sscanf函数一起使用。

上面这些函数都是属于文本操作函数,操作的是文本文件,而接下来我们要学习的是操作二进制文件的函数。

fwrite的使用 

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

上面这个函数的大概意思是:写count个,大小为size的字节的元素到这个流里(stream),从ptr所指向的这个内存开始写。 

struct S
{
	int i;
	float f;
};
#include <stdio.h>
int main()
{
	//打开文件
	FILE* pf = fopen("data.txt", "wb");
	//打开失败
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	struct S s = { 10, 3.14f };
	//从&s这个位置开始写,写一个大小为sizeof(s)的数据到pf中
	fwrite(&s, sizeof(s), 1, pf);

	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

如果要把它看懂的话,就得用二进制的方式来读,这就需要用到fread函数了。

fread的使用 

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

我们会发现这个和fwrite的参数是一样的。其实这个函数与fwrite的功能刚好相反。它是从流中(stream)的数据, 取出count个大小为size的数据放到ptr所指向的那块空间中。并且当fread会返回一个size_t的值,表示读取成功的个数。

#include <stdio.h>
struct S
{
	int i;
	float f;
};
int main()
{
	//打开文件
	FILE* pf = fopen("data.txt", "wb");
	//打开失败
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	struct S s1 = { 10, 3.14f };
	//写入数据
	fwrite(&s1, sizeof(s1), 1, pf);
	fclose(pf);

	pf = fopen("data.txt", "rb");
	struct S s2 = { 0 };
	//从pf中读取一个大小为sizeof(s)的数据放到&s指向的那块空间中
	fread(&s2, sizeof(s2), 1, pf);
	printf("%d %f\n", s2.i, s2.f);//看看是否读取成功
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

从输出的结果来看这个我们写入与读取的操作都是正确的。 

文件的随机读写

fseek的使用

根据文件指针的位置和偏移量来定位文件指针。

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

我们知道当打开一个文件时,文件指针是指向这个文件的起始位置的。如果我们想要读取后面的数据,总不能一个一个的往后读取吧,太不方便了。因此就提供了一个函数fseek,可以让我们从想要的位置开始读取。

参数解析:offset——>偏移量  ; origin——>从哪里开始读取。给我们提供了三个选择:文件的起始位置(SEEK_SET),文件的末尾(SEEK_END),文件指针当前指向的位置(SEEK_CUR) ; stream——>从哪个流开始读取。

#include <stdio.h>
int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//假设我们这个已经在data.txt这个文件中写入abcdefghi
	int ret = fgetc(pf);
	printf("%c\n", ret);

	fseek(pf, 5, SEEK_SET);

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

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

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

注意这个偏移量也是由正负之分的。正的,文件指针就往右偏;负的,文件指针就往左偏。

并且我这个SEEK_SET是从文件的起始地址开始的,如果是使用SEEK_CUR,那么就只要偏移4次就够了,因为读取a之后,文件指针就指向b去了。

ftell的使用 

返回文件指针相对于起始位置的偏移量。

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

#include <stdio.h>
int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//偏移了次
	fseek(pf, 5, SEEK_SET);
	//相较于起始地址,偏移量是5
	int ret = ftell(pf);
	printf("%d\n", ret);

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

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

rewind的使用 

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

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

#include <stdio.h>
int main()
{
	FILE* pf = fopen("data.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fseek(pf, 5, SEEK_SET);
	int ret = fgetc(pf);
	printf("%c\n", ret);

	rewind(pf);
	ret = fgetc(pf);
	printf("%c\n", ret);
	
	fclose(pf);
	pf = NULL;
	return 0;
}

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

这些文件都是fseek那个代码里的文件,也就是这个文件里是:abcdefghi。 

文件读取结束的判定

被错误使用的 feof

牢记:在文件读取过程中,不能用feof函数的返回值直接来判断文件的是否结束。

feof 的作用是:当文件读取结束的时候,判断读取结束的原因是否是:遇到文件尾结束。

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

例如: • fgetc 判断是否为 EOF 。 • fgets 判断返回值是否为 NULL 。

2. 二进文件的读取结束判断,判断返回值是否小于实际要读的个数。

• fread判断返回值是否小于实际要读的个数。

文本文件:

#include <stdio.h>
#include <stdlib.h>
int main()
{
	int c; 
	FILE* fp = fopen("test.txt", "r");
	if (!fp)//fp==NULL 
	{
		perror("File opening failed");
		return EXIT_FAILURE;
	}
	//fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF
	while ((c = fgetc(fp)) != EOF) 
	{
		putchar(c);
	}
	//判断是什么原因结束的
    //ferror是用来判断是不是遇到读取错误
	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;
}

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

二进制文件:

#include <stdio.h>
enum { SIZE = 5 };
int main()
{
	double a[SIZE] = { 1.0,2.0,3.0,4.0,5.0 };
	FILE* fp = fopen("test.bin", "wb"); 
	if (fp == NULL)
	{
		perror("fopen");
		return 1;
	}
	//sizeof * a <——> sizeof(*a) <——> 这个也就是a数组的第一个元素
	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 
	{
		if (feof(fp))//读取错误
		{
			printf("Error reading test.bin: unexpected end of file\n");
		}
		else if (ferror(fp)) //遇到文件末尾
		{
			perror("Error reading test.bin");
		}
	}
	fclose(fp);
	fp = NULL;
	return 0;
}

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

文件缓冲区 

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

C语言之文件操作(万字详解),#C语言标准库函数,C语言,c语言,文件操作

#include <stdio.h>
#include <windows.h>//Sleep函数所需的头文件
int main()
{
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fputs("abcdef", pf);//先将代码放在输出缓冲区
	printf("睡眠10秒-已经写数据了,打开test.txt文件,发现文件没有内容\n");
	Sleep(10000);//休眠10000毫秒
	printf("刷新缓冲区\n");
	fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘)
	printf("再睡眠10秒-此时,再次打开test.txt文件,文件有内容了\n");
	Sleep(10000);
	fclose(pf);
	//注:fclose在关闭文件的时候,也会刷新缓冲区
	pf = NULL;
	return 0;
}

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

好啦!本期文件操作的学习到此就结束了!下一期,我们再一起学习吧!文章来源地址https://www.toymoban.com/news/detail-845927.html

到了这里,关于C语言之文件操作(万字详解)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【c语言】-- 操作符汇总(万字详解)

    📕博主介绍:目前大一正在学习c语言,数据结构,计算机网络。 c语言学习,是为了更好的学习其他的编程语言,C语言是母体语言,是人机交互接近底层的桥梁。 本章来学习操作符。 让我们开启c语言学习之旅吧 温馨提示:这篇文章干货非常多,感兴趣小伙伴一定要认真看

    2024年02月13日
    浏览(42)
  • C语言中的操作符(万字详解)

    🎈个人主页:库库的里昂 🎐CSDN新晋作者 🎉欢迎 👍点赞✍评论⭐收藏 ✨系列专栏C语言初阶、代码小游戏 🤝希望作者的文章能对你有所帮助,有不足的地方请在评论区留言指正,大家一起学习交流!🤗 【前言】 操作符的种类比较多,也是我们在敲代码过程中很常用的知

    2024年02月14日
    浏览(42)
  • C语言--文件操作详解(2)(文本文件和二进制文件,文件读取结束的判定,用函数进行文件的拷贝,文件缓冲区)

    本篇文章主要介绍了文本文件和二进制文件,文件读取结束的判定,如何使用函数进行文件的拷贝,文件缓冲区的相关知识。 以及具有保存功能的八功能通讯录的源码。 据数据的组织形式,数据文件被称为文本文件或者二进制文件。 ①数据在内存中以二进制的形式存储,如

    2024年02月08日
    浏览(48)
  • 万字长文·通俗易懂·一篇包掌握——输入/输出·文件操作(c语言超详细系列)(二)

    前言:Hello,大家好😘,我是心跳sy,上一节我们主要学习了格式化输入输出的基本内容,这一节我们对格式化进行更加深入的了解,对文件概念进行介绍,并且对输入、输出与文件读写的基本概念进行学习,本节主要对printf,scanf深入了解,并介绍文件处理函数,如fprintf,

    2024年02月13日
    浏览(69)
  • C语言标准库(常用函数)详解(含示例)数学公式:math.h

    目录 math.h的介绍 math.h的概述 库中定义的宏: HUGE_VAL 库函数(只讲解常用函数) 三角函数 示例代码 输出 双曲函数 示例代码 输出 指数和对数函数(只含常用函数) 示例代码  输出 常用函数pow,sprt,cbrt,hypot,fabs,abs 代码示例 输出 math.h 一般见于C,C++程序设计, #includema

    2024年02月09日
    浏览(40)
  • C语言中的字符串操作函数自定义实现:标准版与限定长度版

            目录 1. 标准字符串操作函数自定义实现 (a) 自定义strcpy函数 (b) 自定义strcat函数 (c) 自定义strcmp函数 2. 限定长度字符串操作函数自定义实现 (a) 自定义strncpy函数 (b) 自定义strncat函数 (c) 自定义strncmp函数  对字符串的操作是不可或缺的一部分。标准库提供了如strcpy、

    2024年01月21日
    浏览(59)
  • 【C语言】——动态内存管理与文件操作,后面加一个通讯录福利,万字解读,看完你会有一个全新认识

    目录 一.动态内存管理 1.为什么有动态内存管理 2.malloc和free  2.calloc和realloc 3.柔性数组 二.文件操作 1.为什么使用文件  2.二进制文件和文本文件  3.文件的打开和关闭 4.文件的顺序读写 5.文件缓冲区 三.通讯录  1.预处理  2.基本框架 3.初始化函数 4.增加联系人  5.显示联系人

    2024年03月13日
    浏览(39)
  • C++动态库编程 | C++名称改编、标准C接口、extern “C”、函数调用约定以及def文件详解

    目录 1、导入导出声明 2、C++函数名称改编与extern \\\"C\\\" 3、函数调用约定与跨语言调用 3.1、函数调用约定 3.2、跨语言调用dll库接口 3.3、函数调用约定以哪个为准 4、def文件的使用 5、在C++程序中引用ffmpeg库中的头文件链接报错问题 6、最后 VC++常用功能开发汇总(专栏文章列表,

    2024年02月11日
    浏览(66)
  • C语言-> 文件操作(函数满屏)

    ✅作者简介:大家好,我是橘橙黄又青,一个想要与大家共同进步的男人😉😉 🍎个人主页:橘橙黄又青_C语言,数据结构,函数-CSDN博客 目的:学习文件操作,即文件相关函数的学习 在这里首先放置我个人认为好的学习c语言的网站 : cplusplus.com: https://legacy.cplusplus.com/referen

    2024年02月04日
    浏览(41)
  • C语言中的文件操作函数

    首先学习文件指针的相关知识 在C语言中,文件指针是一个指向文件的指针变量,用于定位和操作文件。在C语言中文件指针类型 FILE* 习惯性定义文件指针为 FILE* fp; 文件操作函数在stdio.h的头文件中。所以要进行 顾名思义,这个函数的意思就是打开文件。 函数原型 FILE* fop

    2024年02月03日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包