C语言文件操作(C语言系列21)

发布于:2022-10-29 ⋅ 阅读:(417) ⋅ 点赞:(0)

目录

前言:

1.为什么使用文件

2.什么是文件

2.1程序文件

2.2数据文件

2.3文件名

3.文件的打开和关闭

3.1文件的指针

3.2文件的打开和关闭的具体操作

4.文件的顺序读写

4.1文件顺序读写的函数

4.2内存与键盘和屏幕的关系 

4.3文件与内存的关系 

4.4文件操作函数的演示

5.文件的随机读写

5.1fseek

5.2ftell

5.3rewind

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

7.文件读取结束的判定

7.1被错误使用的feof

8.文件缓冲区

结束语:


前言:

今天小编与大家分享一下C语言中的文件操作都有哪些吧!话不多说直接来上知识。

1.为什么使用文件

使用文件我们就可以将数据直接存放到电脑的硬盘上,做到了数据持久化。

2.什么是文件

在磁盘上的文件是文件,但是在程序设计中,我们一般谈的文件有两种:

  • 程序文件
  • 数据文件

今天我们主要谈的是数据文件。

2.1程序文件

那么什么是程序文件呢?

程序文件包括三个:

  • 源程序文件(后缀为.c)
  • 目标文件(Windows环境后缀为.obj)
  • 可执行程序(Windows环境后缀为.exe)

2.2数据文件

定义:

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

在以前各处理数据的输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显示器上。

  • printf--------------->屏幕
  • scanf-------------->键盘

其实有时候我们会把信息输出到磁盘上,当需要有的时候再从磁盘上把数据读取到内存中使用,这里处理的就是磁盘上的文件。

如下图所示:
 

2.3文件名

一个文件要有一个唯一的文件标识符,以便用户识别和引用。

文件包含3部分:文件路径+文件名主干+文件后缀

列如:c:\code\test.txt

红色部分与上面的三部分一一对应。

为了方便起见,文件标识被称为文件名。

3.文件的打开和关闭

fopen 打开

格式:FILE* fopen(const char* filename,const char* mode)

filename:文件名。

mode:文件的打开方式。

fclose 关闭

格式:FILE* fclose(FILE* stream)

stream:文件指针。

文件的执行步骤:

 代码如下所示:

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
int main()
{
	FILE* pf = fopen("test.txt", "w");
	if (NULL == pf)
	{
		perror("fopen");
		return;
	}
	//写文件
	// 
	// 
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

正常运行结果图:


3.1文件的指针

缓冲文件系统中,关键的概念是“文件类型指针”,简称为“文件指针”。

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

FIEL* pf ;//其中pf是文件指针变量。

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

3.2文件的打开和关闭的具体操作

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

在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指针和文件的关系。

在ANSIC规定中使用fopen函数来打开文件,fclose来关闭文件。具体的代码可以见3中的文件打开与关闭操作。

下面是文件的打开方式:
 

文件的使用方式 含义
“r”(只读) 为了输入数据,打开一个已经存在的文本文件
“w”(只写) 为了输出数据,打开一个文本文件
“a”(追加) 向文本文件的末尾添加数据
“rb”(只读) 为了输入数据,打开一个二进制文件
“wb”(只写) 为了输出数据打开一个二进制文件
“ab”(追加) 向一个二进制尾添加数据

文件有两种打开方式:

  • 相对路径
  • 绝对路径 

代码如下所示:

#define _CRT_SECURE_NO_WARNINGS 1
//相对路径与绝对路径
#include<stdio.h>
int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "w");//相对路径
	FILE* pf = fopen("D:\\code\\test.txt", "w");//绝对路径
	//判断是否正确打开
	if (NULL == pf)
	{
		perror("fopen");
		return;
	}
	//写文件
	//
	// 
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

4.文件的顺序读写

4.1文件顺序读写的函数

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

4.2内存与键盘和屏幕的关系 

4.3文件与内存的关系 

4.4文件操作函数的演示

1.fputc:
格式:int fputc (int character,FILE* stream)

代码如下所示:

#define _CRT_SECURE_NO_WARNINGS 1
//fputc-字符输出函数,写到文件中去
#include<stdio.h>
int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "w");
	//判断是否正确打开
	if (NULL == pf)
	{
		perror("fopen");
		return;
	}
	//写文件
	int i = 0;
	for (i = 0; i < 26; i++)
	{
		fputc('a' + i, pf);
	}
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}


结果如下所示:

2.fgetc:

格式:int fgetc( FILE *stream )

代码如下所示:

#define _CRT_SECURE_NO_WARNINGS 1
//fgetc函数的演示
#include<stdio.h>
int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "r");
	//文件能否打开的判断
	if (NULL == pf)
	{
		perror("fopen");
		return;
	}
	//文件的读操作
	//int i = 0;
	//for (i = 0; i < 20; i++)
	//{
	//	int ch = fgetc(pf);
	//	printf("%c ", ch);
	//}
	int ch = 0;
	while ((ch = fgetc(pf)) != EOF)
	{
		printf("%c ", ch);
	}
	return 0;
}


结果如下所示:

3.fputs

格式:int fputs( const char *string, FILE *stream )

代码如下所示:

#define _CRT_SECURE_NO_WARNINGS 1
//fputs函数
#include<stdio.h>
int main()
{
	FILE* pf = fopen("test.txt", "w");
	if (NULL == pf)
	{
		perror("fopen");
		return;
	}
	//写文件一行一行的写
	fputs("hello\n", pf);
	fputs("world", pf);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}


结果如下所示:

4.fgets

格式:char *fgets( char *string, int n, FILE *stream )

代码如下所示:

#define _CRT_SECURE_NO_WARNINGS 1
//fgets函数
#include<stdio.h>
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (NULL == pf)
	{
		perror("fopen");
		return;
	}
	//读文件-一行一行的读
	char arr[20] = "###########";
	fgets(arr, 20, pf);
	printf("%s ", arr);

	fgets(arr, 20, pf);
	printf("%s ", arr);
	return 0;
}


结果如下所示:

5.fprintf

格式:int fprintf( FILE *stream, const char *format [, argument ]...);

代码展示:

#define _CRT_SECURE_NO_WARNINGS 1
//fprintf函数演示
struct S
{
	char name[20];
	int age;
	float score;
};
#include<stdio.h>
int main()
{
	struct S s = { "zhangsan",20,99.0f };
	//打开文件
	FILE* pf = fopen("test.txt", "w");
	if (NULL == pf)
	{
		perror("fopen");
		return;
	}
	//写文件
	fprintf(pf, "%s %d %lf", s.name, s.age, s.score);
	fclose(pf);
	pf = NULL;
	return 0;
}


结果如下所示:


6.fscanf

格式:int fscanf( FILE *stream, const char *format [, argument ]... );
代码展示:

#define _CRT_SECURE_NO_WARNINGS 1
//fscanf函数展示
#include<stdio.h>
struct S
{
	char name[20];
	int age;
	float score;
};
int main()
{
	struct S s = { 0 };
	//把s中的数据写到文件中
	FILE* pf = fopen("test.txt", "r");
	if (NULL == pf)
	{
		perror("fopen");
		return;
	}
	//读文件
	fscanf(pf, "%s %d %f", s.name, &(s.age), &(s.score));
	printf("%s %d %f", s.name, s.age, s.score);
	fclose(pf);
	pf = NULL;
	return 0;
}


结果如下所示:

7.fwrite 

格式:size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );
代码展示:

#define _CRT_SECURE_NO_WARNINGS 1
//fwrite函数演示
#include<stdio.h>
struct S
{
	char name[20];
	int age;
	float score;
};
int main()
{
	struct S s = { "zhangsan",20,99.0f };
	//将s中的数据写到文件中
	//打开文件
	FILE* pf = fopen("test.txt", "wb");
	if (NULL == pf)
	{
		perror("fopen");
		return;
	}
	//二进制的写文件
	fwrite(&s, sizeof(s), 1, pf);
	//关闭文件
	fflush(pf);
	fclose(pf);
	pf = NULL;
	return 0;
}


结果如下所示:

8.fread

格式:size_t fread( void *buffer, size_t size, size_t count, FILE *stream );
代码展示:

#define _CRT_SECURE_NO_WARNINGS 1
//fread函数演示
#include<stdio.h>
struct S
{
	char name[20];
	int age;
	float score;
};
int main()
{
	struct S s = { 0 };
	//打开文件
	FILE* pf = fopen("test.txt", "rb");
	if (NULL == pf)
	{
		perror("fopen");
		return;
	}
	//二进制的读文件
	fread(&s, sizeof(s), 1, pf);
	printf("%s %d %f", s.name, s.age, s.score);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}


结果如下所示:

 这里强调一下对于任何一个C程序,FILE*只要运行就会默认打开三个流:

  • stdin:标准输入流——键盘
  • stdout:标准输出流——屏幕
  • stderr:标准错误流——屏幕

scanf/fscanf/sscanfprintf/fprintf/scanf的区别:

1.

  • scanf:按照一定的格式从键盘输出数据。
  • printf:按照一定的格式刷把数据打印(输出)到屏幕上。 

适用于标准输入/输出流的格式化的输入/输出语句。 

2. 

  • fscanf:按照一定的格式从输入流(文件/stdin)输入数据。
  • fprintf:按照一定的格式向输出流(文件/stdout)输出数据。

适用于所有的输入/输出流的格式化输入/输出语句。

3. 

  • sscanf:从字符串中按照一定的格式读取格式化的数据。
  • sprintf:把格式化的数据按照一定的格式转化成字符串。

5.文件的随机读写

注意:以下所有代码演示均是基于下面的代码来演示的!!!

#define _CRT_SECURE_NO_WARNINGS 1
//fputs
#include<stdio.h>
int main()
{
	FILE* pf = fopen("test1.txt", "w");
	if (NULL == pf)
	{
		perror("fopen");
		return;
	}
	//写文件
	fputs("zhangsan", pf);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

上述代码运行结果: 

5.1fseek

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

格式:int fseek( FILE *stream, long offset, int origin );

代码展示:

#define _CRT_SECURE_NO_WARNINGS 1
//fseek函数演示
#include<stdio.h>
int main()
{
	FILE* pf = fopen("test1.txt", "r");
	if (NULL == pf)
	{
		perror("fopen");
		return;
	}
	//zhangsan
	int ch = fgetc(pf);
	printf("%c\n", ch);//这时指针已经指向了h
	fseek(pf, 2, SEEK_CUR);//SEEK_CUR表示从当前的位置开始
	//表示从h开始指针向后移动两个位置,到n
	ch = fgetc(pf);
	printf("%c\n", ch);//打印n,指针向后移动到g
	fseek(pf, -2, SEEK_END);//SEEK_END表示从最后面的位置开始
	ch = fgetc(pf);
	printf("%c\n", ch);//打印a,指针向后移动一位指向n

	fseek(pf, 3, SEEK_SET);//SEEK_SET表示从最前面的位置开始
	ch = fgetc(pf);
	printf("%c\n", ch);
	return 0;
}


结果如下所示:

5.2ftell

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

格式:long ftell( FILE *stream );

代码展示:

#define _CRT_SECURE_NO_WARNINGS 1
//ftell函数演示
#include<stdio.h>
int main()
{
	FILE* pf = fopen("test1.txt", "r");
	if (NULL == pf)
	{
		perror("fopen");
		return;
	}
	int ch = fgetc(pf);
	printf("%c\n", ch);
	//读取了一个字符指针向后移动一位
	long i = 0;
	i = ftell(pf);
	printf("%d\n", i);//打印1

	ch = fgetc(pf);
	printf("%c\n", ch);
	//又读取了一个字符指针向后移动一位
	i = ftell(pf);
	printf("%d\n", i);//打印2
	fclose(pf);
	pf = NULL;
	return 0;
}


结果如下所示:

5.3rewind

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

格式:void rewind( FILE *stream ); 

代码展示:

#define _CRT_SECURE_NO_WARNINGS 1
//rewind函数演示
#include<stdio.h>
int main()
{
	FILE* pf = fopen("test1.txt", "r");
	if (NULL == pf)
	{
		perror("fopen");
		return;
	}
	int ch = 0;
	ch = fgetc(pf);//得到z
	printf("%c\n", ch);

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

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

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

	printf("\n");

	rewind(pf);//使得指针回到最开始的位置
	ch = fgetc(pf);//z
	printf("%c\n", ch);
	return 0;
}


结果如下所示:

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

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

数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。

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

那么一个数据在内存中又是如何存储的呢?

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


7.文件读取结束的判定

7.1被错误使用的feof

牢记:在文件读取过程当中,不能用feof函数的返回值直接来判断文件是否结束,而是应用于当前文件读取结束的时候,判断是读取失败结束,还是遇到文件尾而结束的。

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

例如:

fgetc判断是否为EOF。

fgets判断返回值是否为NULL。

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

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

8.文件缓冲区

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

故因为存在缓冲区,C语言在操作文件的时候,需要做到刷新缓冲区或者在文件操作结束的时候关闭文件。如果不做,可能会导致读写文件的问题。 

结束语:

有关于文件操作的知识点小编就分享到这里啦,希望对大家有所帮助,想要学习的同学记得关注小编和小编一起学习吧!如果文章中有任何错误也欢迎各位大佬及时为小编指点迷津(在此小编先谢过各位大佬啦!)