C语言-文件操作(13.1)

目录

思维导图:

1. 为什么使用文件

2. 什么是文件

2.1 程序文件

2.2 数据文件

2.3 文件名

3. 文件的打开和关闭

3.1 文件指针

3.2 文件的打开和关闭

4. 文件的顺序读写

4.1 对比一组函数

5. 文件的随机读写

5.1 fseek

5.2 ftell

5.3 rewind

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

7. 文件读取结束的判定

7.1 feof

8. 文件缓冲区

写在最后:


思维导图:

1. 为什么使用文件

在学习通讯录的时候,我们往通讯录里添加信息,

但是,当我们关闭程序的时候,存放在通讯录的内容就销毁了。

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

如果把通讯录数据放文件了,下一次打开也能继承上一次的数据。

2. 什么是文件

磁盘上的文件就是文件。

但是在程序设计中,我们一般谈的文件有两种:程序文件和数据文件。

2.1 程序文件

程序文件包括:

1.源程序文件(后缀为.c)

2.目标文件(windows环境后缀为.obj)

3.可执行程序(windows环境后缀为.exe)

2.2 数据文件

 文件的内容不一定是程序,而是程序运行时读写的数据,

比如程序运行需要从中读取数据的文件,或者输出内容的文件。

2.3 文件名

一个文件有一个唯一的文件标识,

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

例: c:\code\test.txt

3. 文件的打开和关闭

3.1 文件指针

在C语言中,我们需要知道的是 FILE* 是文件类型的指针,

他的具体实现是C语言已经帮我们实现了的。

3.2 文件的打开和关闭

文件的打开使用的是 fopen 函数:

 

 文件的关闭使用的是 fclose 函数:

 

直接上代码:

例:

int main()
{
    //打开并读取这个文件名的文件
	FILE* pf = fopen("test.txt", "r");

    //判断打开文件是否成功
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//读文件

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

输出:

输出;fopen: No such file or directory

因为磁盘中并没有这个文件,所以报错。

对文件的操作还有很多:

文件使用方式 含义 如果指定文件不存在
“r”(只读) 为了输入数据,打开一个已经存在的文本文件 出错
“w”(只写) 为了输出数据,打开一个文本文件 建立一个新的文件
“a”(追加) 向文本文件尾添加数据 建立一个新的文件
“rb”(只读) 为了输入数据,打开一个二进制文件 出错
“wb”(只写) 为了输出数据,打开一个二进制文件 建立一个新的文件
“ab”(追加) 向一个二进制文件尾添加数据 出错
“r+”(读写) 为了读和写,打开一个文本文件 出错
“w+”(读写) 为了读和写,建议一个新的文件 建立一个新的文件
“a+”(读写) 打开一个文件,在文件尾进行读写 建立一个新的文件
“rb+”(读写) 为了读和写打开一个二进制文件 出错
“wb+”(读写) 为了读和写,新建一个新的二进制文件 建立一个新的文件
“ab+”(读写) 打开一个二进制文件,在文件尾进行读和写 建立一个新的文件

之后再用到的时候需要对其一定的了解。

4. 文件的顺序读写

接下来我们学习一些对文件读写的函数,

这样我们才能更好的操作文件。

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

 我们通过一些例子来学习一下上述函数:

字符输出函数 fputc:

例1:

#include <stdio.h>

int main()
{
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}
	
	//写文件
	fputc('a', pf);
		
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

我们先通过 fputc 函数写了个字符‘a’进文件test.txt中。

打开文件:

 文件中真的写入了字符‘a’。

字符输入函数 fgetc:

 

我们还能通过 fgetc 函数读文件验证一下:

#include <stdio.h>

int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//读文件
	int ch = fgetc(pf);
	printf("%c\n", ch);
		
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

输出:

 我们发现真的读出并打印出了字符‘a’。

接下来我们学习一下 fputs 函数和 fgets 函数。

 

例:

#include <stdio.h>

int main()
{
	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//写文件
	fputs("welcome to my blog\n", pf);
	fputs("happy new year\n", pf);

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

输出:

写完文件之后,自然是读出来看看:

 

#include <stdio.h>

int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//读文件
	char buf[20] = { 0 };
	fgets(buf, 20, pf);//只读一行
	printf("%s\n", buf);

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

我们发现 fgets 函数只读一行:

 只要我们再用一次 fgets 函数就行:

#include <stdio.h>

int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//读文件
	char buf[20] = { 0 };
	fgets(buf, 20, pf);//只读一行
	printf("%s", buf);

	fgets(buf, 20, pf);
	printf("%s", buf);

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

输出:

 接下来是 fprintf 函数,格式化写入文件:

 例:

#include <stdio.h>

typedef struct S
{
	char name[20];
	int age;
	float score;
}S;

int main()
{
	S s = { "zhagnsan",120,2.22 };

	S* ps = &s;

	FILE* pf = fopen("test.txt", "w");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//格式化写入文件
	fprintf(pf, "%s %d %f\n", ps->name, ps->age, ps->score);

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

输出:

 文件成功写入了,

接下来是格式化输出 fscanf 函数:

例:

#include <stdio.h>

typedef struct S
{
	char name[20];
	int age;
	float score;
}S;

int main()
{
	S s = { "zhagnsan",120,2.22 };
	S* ps = &s;

	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//格式化的读文件
	fscanf(pf, "%s %d %f", ps->name, &(ps->age), &(ps->score));
	printf("%s %d %f\n", ps->name, ps->age, ps->score);

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

 输出:

 最后是二进制写入文件 fwrite 函数:

#include <stdio.h>

typedef struct S
{
	char name[20];
	int age;
	float score;
}S;

int main()
{
	S s = { "zhagnsan",120,2.22 };
	S* ps = &s;
	FILE* pf = fopen("test.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//写文件
	fwrite(&s, sizeof(S), 1, pf);

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

输出:

 因为写进去的是二进制的形式,所以就出现了一些你看不懂的东西。

接着,我们用二进制的形式读取文件 fread 函数:

#include <stdio.h>

typedef struct S
{
	char name[20];
	int age;
	float score;
}S;

int main()
{
	S s = { "zhagnsan",120,2.22 };
	//S s = {0};
	S* ps = &s;
	FILE* pf = fopen("test.txt", "wb");
	if (pf == NULL)
	{
		perror("fopen");
		return 1;
	}

	//读文件
	fread(&s, sizeof(S), 1, pf);
	printf("%s %d %f", s.name, s.age, s.score);

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

 输出:

 成功打印出来。

4.1 对比一组函数

scanf / fscanf / sscanf

printf / fprintf / sprintf

 

例:

#include <stdio.h>

typedef struct S
{
	char name[20];
	int age;
	float score;
}S;

int main()
{
	S s = { "zhagnsan",120,2.22 };
	char buf[100] = { 0 };
	sprintf(buf, "%s %d %f", s.name, s.age, s.score);
	printf("%s\n", buf);
	S tmp;
	sscanf(buf, "%s %d %f", tmp.name, &(tmp.age), &(tmp.score));
	printf("%s %d %f", tmp.name, tmp.age, tmp.score);
	return 0;
}

输出:

输出:
zhagnsan 120 2.220000
zhagnsan 120 2.220000

5. 文件的随机读写

5.1 fseek

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

5.2 ftell

返回文件指针相对于起始位置的偏移量。(计算文件指针所在位置)

5.3 rewind

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

事先在文件中存储"abcdef"。

例:

#include <stdio.h>

int main()
{
	FILE* pf = fopen("test.txt", "r");
	if (pf == NULL)
	{
		perror("fopen");
	}
	else
	{
		int ch = fgetc(pf);
		printf("%c\n", ch);
		ch = fgetc(pf);
		printf("%c\n", ch);		
		ch = fgetc(pf);
		printf("%c\n", ch);

		fseek(pf, -2, SEEK_CUR);//文件指针偏移
		ch = fgetc(pf);//查看偏移量
		printf("%c\n", ch);
		rewind(pf);//文件指针返回起始位置

		printf("%d\n", ftell(pf));

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

输出:

输出:
a
b
c
b
0

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

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

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

例:

#include <stdio.h>

int main()
{
	int a = 10000;
	FILE* pf = fopen("test.txt", "wb");
	fwrite(&a, 4, 1, pf);//二进制的形式写到文件中
	fclose(pf);
	pf = NULL;
	return 0;
}

然后再VS中打开这个文件:

然后就能看到:

 

 我们存进内存的数以小端形式存储,

这里展现出的是以十六进制打印出来的结果,其本质就是二进制数。

7. 文件读取结束的判定

7.1 feof

这个函数是用于判断文件读取结束的原因:

如果文件是因为读取失败而结束就返回0,

如果文件是遇到文件尾结束就返回非0数。

8. 文件缓冲区

如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),

然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。

缓冲区的大小根据C编译系统决定的。

例:

 如果缓冲区没满,主动刷新缓冲区也会将数组存入磁盘。

而C语言中调用 fclose 函数就会刷新一下,

所以,写程序如果打开了文件,记得一定要关闭,否则肯数据就丢失了。

写在最后:

以上就是本篇文章的内容了,感谢你的阅读。

如果喜欢本文的话,欢迎点赞和评论,写下你的见解。

如果想和我一起学习编程,不妨点个关注,我们一起学习,一同成长。

之后我还会输出更多高质量内容,欢迎收看。

猜你喜欢

转载自blog.csdn.net/Locky136/article/details/128306819