1.为什么使用文件?

2.什么是文件?

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

4.文件的打开和关闭

5.文件的顺序读写

6.文件的随机读写

7.文件读取结束的判定

8.文件缓冲区


1.为什么使用文件?

如果没有文件,我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就会丢失,如果要将数据进行持久化保存,我们可以使用文件。

2.什么是文件?

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

2.1程序文件

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

2.2数据文件

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

2.3文件名

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

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

根据数据的组织形式,数据文件被称为文本文件或者二进制文件
数据在内存中以二进制形式存储,如果不加以转换的输出到外存的文件中,就是二进制文件
以ASCII字符形式存储的文件就是文本文件
一个数据在文件中是怎么存储的?
在这里插入图片描述

4.文件的打开和关闭

4.1流和标准流

4.1.1流

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

4.1.2标准流

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

  • stdin-标准输入流,在大多数环境中从键盘输入,scanf函数就是从标准输入流中读取数据。
  • stdout-标准输出流,在大多数环境中输出至显示器界面上,printf函数就是将信息输出到标准输出流中。
  • stderr-标准错误流,在大多数环境中输出到显示器界面。
    stdin、stdout、stderr三个流的类型是:FILE*,通常称为文件指针
    C语言中,就是通过FILE*的文件指针来维护流的各种操作的。

4.2文件指针

每一个被使用的文件在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息。这些信息保存在一个结构体变量中。该结构体类型由系统声明,取名FILE
一般都是通过一个FILE指针来维护这个FILE结构体变量:
在这里插入图片描述

4.3文件的打开与关闭

文件在读写前应打开文件,读写后关闭文件
再打开文件的同时,都会返回一个FILE*的指针变量指向该文件,相当于建立了指针和文件的关系。

//打开文件
FILE* fopen(const char* filename, const char* mode);
//关闭文件
int fclose(FILE* stream);

mode表示文件打开方式,下面都是文件的打开模式在这里插入图片描述
示例代码:

int main()
{
	FILE* pf;
	//打开文件s
	pf = fopen("test.txt", "w");
	//文件操作
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fputs("absda", pf);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

5.文件的顺序读写

5.1顺序读写的介绍

在这里插入图片描述
代码示例:

int main()
{
	//1.打开文件
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//2.读文件
	char arr[10] = { 0 };
	fgets(arr, 10, pf);
	printf("%s",arr);
	//3.关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}
int main()
{
	//1.打开文件
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//2.读文件
	char arr[10] = { 0 };
	//fgets函数返回的是数组arr的首地址
	while (fgets(arr, 10, pf) != NULL)
	{
		printf("%s", arr);
	}
	//3.关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}
//fputc适用所有输出流
int main()
{
	fputc('a', stdout);
	return 0;
}

5.2对比一组函数:

  • scanf/fsanf/sscanf
  • printf/fprintf/sprintf
    scanf - 从标准输入流上读取格式化数据。
    fscanf - 从指定的输入流读取格式化的数据。
    sscanf - 在字符串中读取格式化数据。
    printf - 把数据以格式化的形式打印在标准输出流上。
    fprintf - 把数据以格式化的形式打印在指定的输出流上。
    sprinf - 把格式化的数据转化成字符串。
struct S
{
	char name[20];
	int age;
	float score;
};
int main()
{
	struct S s = { 0 };
	//从文件中读取数据赋值给s
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读文件
	fscanf(pf, "%s %d %f", s.name, &s.age, &s.score);
	//打印在屏幕上看看
	printf("%s %d %f", s.name, s.age, s.score);
	return 0;
}
struct S
{
	char name[20];
	int age;
	float score;
};
int main()
{
	struct S s = {"张三",19,92.4};
	//把s中数据传到文件中
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//给文件传数据
	fprintf(pf, "%s %d %f", s.name, s.age, s.score);
	fclose(pf);
	pf = NULL;
	return 0;
}

6.文件的随机读写

6.1fseek

根据文件指针的位置和偏移量来定位文件指针(文件内容的光标)。

int fseek(FILE* stream,long int offset,int orign);

例子:

/*fseek example*/
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	int ch = fgetc(pf);//a
	//fseek(pf, 4, SEEK_CUR);//h
	//fseek(pf, 5, SEEK_SET);//h
	fseek(pf, -4, SEEK_END);//k
	ch = fgetc(pf);
	printf("%c", ch);
	fclose(pf);
	pf = NULL;
	return 0;
}

6.2ftell

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

long int ftell(FILE* stream);

6.3rewind

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

void rewind(FILE* stream);

7.文件读取结束的判定

7.1被错误使用的feof

feof作用是:当文件读取结束时候,判断读取结束的原因是否是:遇到文件结尾结。不能用feof函数的返回值直接来判断文件是否结束。

文件读取结束(文件遇到EOF)原因:

  1. 遇到文件末尾。 --feof
  2. 读取的时候遇到错误。 --ferror
    文本文件的例子:
int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	//读取
	int ch = 0;
	while ((ch = fgetc(pf)) != EOF)
	{
		printf("%c", ch);
	}
	//判断什么原因导致读取结束的
	if (feof(pf) != NULL)
	{
		printf("遇到文件末尾,读取正常结束");
	}
	else if (ferror(pf))
		perror("fgetc");
	fclose(pf);
	pf = NULL;
	return 0;
}

8.文件缓冲区

缓冲文件系统是指系统自动地在内存中为程序每一个正在使用的文件开辟一块“文件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区才一起送到磁盘上。如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后从缓冲区逐个将数据送到程序数据区。缓冲区大小由C编译系统决定。
在这里插入图片描述

int main()
{
	FILE* pf = fopen("text.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	fputs("abcdef", pf);//将代码放入缓冲区
	printf("睡眠10秒-已经写好数据,打开test.txt,发现文件没有内容\n");
	Sleep(10000);
	printf("刷新缓冲区");//刷新缓冲区能将输出缓冲区的数据写到文件中(磁盘)
	fflush(pf);
	printf("在睡眠10秒,再次打开test.txt文件,文件有内容了");
	//fclose在关闭文件时会刷新输出缓冲区,因此要Sleep来区分
	Sleep(10000);
	fclose(pf);
	pf = NULL;
	return 0;
}

结论:因为有缓冲区的存在,C语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文件。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐