C语言中文件操作详解

系列文章目录



前言

C文件,是程序设计中的一个重要概念。所谓“文件”一般是指存储在外部介质上数据的集合。一批文件是以数据的形式存放在外部介质(如磁盘)上的。操作系统是以文件为单位对数据进行管理的,也就是说,如果想找存在外部介质上的数据,必须先按文件名找到指定的文件,然后再从该文件中读取数据。

一、文件的定义和分类

1.程序文件

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

2.数据文件

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

二、文件的类型

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

int main()
{
    
    
	int a = 10000;
	FILE* pa = fopen("bin.bat", "wb");
	if (pa == NULL)
	{
    
    
		printf("%s\n", strerror(errno));
		return 1;
	}
	else
	{
    
    
		fwrite(&a, sizeof(int), 1, pa);
		printf("文件写入成功!\n");
		fclose(pa);
		pa = NULL;
	}
	return 0;
}

16进进制形式显示:如下图:在这里插入图片描述
在这里插入图片描述

二、文件缓冲区

ANSIC 标准采用“缓冲文件系统”处理的数据文件的,所谓缓冲文件系统是指系统自动地在内存中为程序中每一个正在 使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘 上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐 个地将数据送到程序数据区(程序变量等)。缓冲区的大小根据C编译系统决定的。代码如下:
#define _CRT_SECURE_NO_WARNINGS   1
#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<Windows.h>
int main()  //输入缓冲区的理解
{
    
    
	FILE* pa = fopen("data.txt", "w");  //打开文件
	if (pa == NULL)
	{
    
    
		printf("%s\n", strerror(errno));
	}
	else                                //写进文件
	{
    
    
		fputs("abcde", pa);
		printf("睡眠10s,写进缓冲区的数据!\n");
		Sleep(10000);
		fflush(pa);  //注意fflush在vs高的版本不能使用
		printf("在睡眠10s,此时打开data.txt文档,就有数据!\n");
		Sleep(10000);
	}
		fclose(pa);
		pa = NULL;                 //关闭文件
	return 0;
}

在这里插入图片描述

三.文件的顺序读写

1.字符输入函数和字符输出函数

代码如下:

#define _CRT_SECURE_NO_WARNINGS   1
#include<stdio.h>
#include<string.h>
#include<errno.h>
//int main() //文件操作的相关问题
//{
    
    
//	//fopen函数如果是以写的形式打开
//	//如果文件不存在,会创建这个文件
//	//如果文件存在,会清空文件的内容
//	//fopen函数如果是以读的形式打开
//	//文件不存在则文件打开失败
//	FILE* pa = fopen("data.txt", "r"); //Opens for reading. If the file does not exist or cannot be found, the fopen call fails.
//	//FILE* pa = fopen("data.txt", "w"); //Opens an empty file for writing. If the given file exists, its contents are destroyed.
//	if (pa == NULL)
//	{
    
    
//		printf("文件打开失败!\n");
//		printf("%s\n", strerror(errno));
//		return 1; //失败返回
//	}	
//	else
//	{
    
    
//		int i = 0;
//		for (i = 'a'; i <= 'z'; i++)
//		{
    
    
//			fputc(i , pa);
//		}
//		printf("写入文件成功!\n");
//	}
//	             //读写文件
//	fclose(pa); //关闭文件
//	pa = NULL;
//	return 0;
//}
// 相对路径
// ../表示上一级目录
// ./当前目录
// ./文件夹//.txt 下一级路径
// ../../上上级目录

// 绝对路径 从根目录开始写的路径 D:\visua stdio 2013代码\文件操作的相关问题\文件操作的相关问题

int main() //fgetc适合于所以输入流
{
    
    
	//打开文件
	FILE* pa =fopen("data.txt", "r");
	if (pa == NULL)
	{
    
    
		printf("文件打开失败!\n");
		printf("%s\n", strerror(errno));
		return 1;
	}
	//读取文件
	/*int ch = fgetc(pa);
	printf("%c\n", ch);*/
	int ch = 0;
	while ((ch = fgetc(pa)) != EOF)
	{
    
    
		printf("%c", ch);
	}
	printf("\n");
	//关闭文件
	fclose(pa);
	pa = NULL;
	return 0;
}


//int main() 补充,键盘上输入,其中getchar()putchar()只能从键盘上输入,屏幕上输出,适用于标准输入、输出函数
//{
    
    
//	int ch = 0;
//	while ((ch = fgetc(stdin)) != EOF)
//	{
    
    
//		printf("%c\n", ch);
//	}
//	return 0;
//}

2.文本行输入函数和文本行输出函数

代码如下:

#define _CRT_SECURE_NO_WARNINGS   1
#include<stdio.h>
#include<errno.h>
#include<string.h>

//int main() //fputs文本行输出流函数
//{
    
    
//	FILE* pa = fopen("data.txt", "w");
//	if (pa == NULL)
//	{
    
    
//		printf("文件打开失败!\n");
//		printf("%s\n", strerror(errno));
//	}
//	else
//	{
    
    
//		//写一行数据
//		fputs("bit education\n", pa);
//		fputs("bit NB\n", stdout);//文本行打印到屏幕上
//		printf("文件写入成功!\n");
//	}
//	fclose(pa);
//	pa = NULL;
//	return 0;
//}

int main() //fgets适用于所有输入流
{
    
    
	char arr[100] = {
    
     0 };
	FILE* pa = fopen("data.txt", "r");
	if (pa == NULL)
	{
    
    
		printf("打开文件失败!\n");
		printf("%s\n", strerror(errno));
		return 1;
	}
	else
	{
    
    
		//读一行数据
		fgets(arr, 6, pa); //其中bit3个字符再包括一个\0就是4个字符,\0是字符串结束标志
		printf("%s\n", arr);
		printf("文件读入成功!\n");

		//读多行数据
	/*	while (fgets(arr, 4, pa) != NULL)
		{
			printf("%s", arr);
		}*/

		//也可以从屏幕上输入,标准输入流读取
		/*fgets(arr, 4, stdin);*/
		printf("%s", arr);
		printf("\n");
	}
	return 0;
}

3.格式化输入函数和格式化输出函数

代码如下:

#define _CRT_SECURE_NO_WARNINGS   1
#include<stdio.h>
#include<errno.h>
#include<string.h>
struct stu
{
    
    
	char name[20];
	int age;
	float score;
};
//int main()   //fprintf的相关问题
//{
    
    
//	struct stu s = { "鱼王", 20, 66.5f };
//	struct stu* pb = &s;
//	FILE* pa = fopen("data.txt", "w"); //打开文件
//	if (pa == NULL)
//	{
    
    
//		printf("%s\n", strerror(errno));
//		return 1;
//	}
//	else                             //格式化的写入文件
//	{
    
    
//		fprintf(pa, "%s %d %f", pb->name, pb->age, pb->score);
//		printf("文件写入成功!\n");
//		//printf("%s %d %f\n", s.name, s.age, s.score);
//	}
//	fclose(pa);                     //关闭文件
//	pa = NULL;
//	return 0;
//}

int main()  //fscanf的相关问题
{
    
    
	struct stu s = {
    
     0 };
	struct stu* pb = &s; 
	FILE* pa = fopen("data.txt", "r");
	if (pa == NULL)
	{
    
    
		printf("%s\n", strerror(errno));
		return 1;
	}
	else    //格式化的读取文件,fscanf在文件流上读取数据到文件中在printf打印输送到屏幕上
	{
    
    
		fscanf( pa,"%s%d%f", pb->name, &(pb->age), &(pb->score));
		//fscanf( stdin, "%s%d%f", pb->name, &(pb->age), &(pb->score)); //也可以从键盘上读取
		printf("%s %d %f\n", s.name, s.age, s.score);
		//fprintf(stdout, "%s %d %f\n", s.name, s.age, s.score);
	}
	fclose(pa);
	pa = NULL;
	return 0;
}
1.区分scanf,printf,fscanf,fprintf,sscanf,sprintf

1.scanf、printf适用于标准的输入输出流的格式化输入输出语句。
2.fscanf、fprintf适用于所有的标准输入输出流的格式化输入输出语句。
3.sscanf、sprintf可以把结构化的数据转化为字符串,也可以把字符串中读取格式化的数据。
格式化数据的定义:某种数据的格式。

三.文件的随机读写、文件结束标志

1.fseek、ftell、rewind、feof函数

代码如下:

#define _CRT_SECURE_NO_WARNINGS   1
#include<stdio.h>
#include<string.h>
#include<errno.h>
int main() //fseek的相关问题,根据文件指针的位置和偏移量来定位文件指针。
{
    
    
	FILE* pa = fopen("data.txt", "r");
	if (pa == NULL)
	{
    
    
		printf("%s\n", strerror(errno));
	}
	else
	{
    
    
		int ch = 0;

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

		//fseek根据文件指针的位置和偏移量来定位文件指针。
		//fseek(pa,0, SEEK_CUR);//流,SEEK_CUR文件当前位置 ,起始位置偏移两个字节
		//fseek(pa,0, SEEK_SET); //流,SEEK_SET文件起始位置,起始位置就是a
		//fseek(pa, -3, SEEK_END); //流,SEEK_END文件结束标志,结束标志是\0,所以当offset为0 时,读取到的是\0
		/*ch = fgetc(pa);
		printf("%c\n", ch);*/

		//rewind(pa); //rewind让文件指针的位置回到文件的起始位置
		//printf("%d\n", ftell(pa)); //ftell返回文件指针相对于起始位置的偏移量
		//printf("%c\n", ch);
		
		while ((ch = fgetc(pa)) != EOF)
		{
    
    
			printf("%c ", ch);
		}
		printf("\n");
		if (ferror(pa))
		{
    
    
			printf("读取时发生错误,失败而结束!\n");
		}
		else if (feof(pa))
		{
    
    
			printf("遇到文件末尾结束!\n");
		}
	}
	fclose(pa);
	pa = NULL;
	return 0;
	}
	//下面文件结束的注意事项
	当我们使用fgetc读取的时候,1.发生错误结束了 2.读取到文件末尾结束了 EOF结束
	当我们使用fgets读取的时候 1.发生错误结束啦 2.读取到文件末尾结束了 NULL结束
	当我们使用fread发现实际读取的个数小于要求读取的最大个数 例如要求读取5个,实际读取4个就结束了

	    文件结束判定
		被错误使用的 feof
		牢记:在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束。
		而是应用于当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束。
		1. 文本文件读取是否结束,判断返回值是否为EOF (fgetc),或者NULL(fgets)
		例如:
		fgetc判断是否为EOF.
		fgets判断返回值是否为NULL.
		2. 二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。
		例如:
		fread判断返回值是否小于实际要读的个数。

总结

以上就是今天要讲的内容,本文仅仅简单介绍了C语言中部分文件操作的用法,文件能使我们便捷地保存数据,不会让数据丢失。另外,如果上述有任何问题,请懂哥指教,不过没关系,主要是自己能坚持,更希望有一起学习的同学可以帮我指正,但是如果可以请温柔一点跟我讲,爱与和平是永远的主题,爱各位了。
在这里插入图片描述

扫描二维码关注公众号,回复: 12816708 查看本文章

猜你喜欢

转载自blog.csdn.net/qq_44918090/article/details/115021762
今日推荐