C语言文件操作详解

为什么需要文件操作

其实我们上一期博客时已经提到了一些了。之前写的通讯录(静态版)中有两个问题。

一.通讯录的大小是固定的,当通讯录人数达到最大容量时,程序就会出错。
二.每次运行都需要自己输入数据,而且当程序关闭后我们输入的信息都会消失,重新打开后通讯录啥也没有了又是空的。

其中第一个问题我们在上一期博客中的动态内存分配中已经解决了。今天我们解决第二个问题,通过学习文件操作函数,达到能够将我们输入的信息保存在文件中,并且在下一次运行时程序会将文件中的内容重新读取到通讯录中。

一. 什么是文件?

在程序设计中,我们通过文件的功能将文件分为两类,数据文件和程序文件。

1 程序文件:比如我们的C语言程序文件,以.c为后缀的源文件就是程序文件中的一种。还有在Windows系统中比较常见的.exe文件,即可执行程序文件,也是程序文件的一种。
2 数据文件:数据文件的内容不一定是程序,有可能是程序运行时需要读取的数据。比如程序需要从中读取信息的文件。

在以前学习的内容中,所处理数据的输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显示器上。
而我们这一期需要学习的是将信息输出到磁盘上保存,当需要的时候再从磁盘输入至内存中进行操作。

1.1 文件名

一个文件要有一个唯一的文件标识,以便用户识别和引用。
文件名包含3部分:文件路径+文件名主干+文件后缀
例如:C:\test\test.c

二.文件的打开与关闭

2.1 文件指针

缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”。
每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名
字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统
声明的,取名FILE.
例如,VS2013编译环境提供的 stdio.h 头文件中有以下的文件类型申明:

struct _iobuf {
char *_ptr;
int _cnt;
char *_base;
int _flag;
int _file;
int _charbuf;
int _bufsiz;
char *_tmpfname;
};
typedef struct _iobuf FILE;

需要注意的是,不同的编译器中FILE类型的内容可能是不同的。
创建FILE*的指针变量格式如下:

FILE* pf;

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

图解:
在这里插入图片描述

2.2 打开与关闭文件

基本语法:

//打开文件
FILE* pf = fopen("文件名","打开方式");
//使用文件
...
//关闭文件
fclose(pf);
pf=NULL;

其中打开方式有以下几种:
在这里插入图片描述

2.3 文件的顺序读写

在这里插入图片描述

2.4 文件的随机读写

2.4.1 随机读写的函数——fseek

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

关于三个形参的介绍
在这里插入图片描述
这里我们简单概括:
在这里插入图片描述
需要注意的一点是offset向后偏移取正值,向前偏移取正值。

2.4.2 计算文件指针相对于起始位置的偏移量的函数——ftell

在这里插入图片描述
这个函数相对简单,可以计算文件指针相对于起始位置的偏移量,具体使用可以看下面的使用案例。

2.4.3 让文件指针重新指向起始位置的函数——rewind

在这里插入图片描述
也是不需要多介绍的函数,请看下面的案例吧。

三. 文件操作案例

3.1 在当前项目中生成一个.txt文件,并且向其中输入"Hello World"

在这里插入图片描述
这是我的项目路径.
代码如下:

#include <stdio.h>
int main()
{
	//打开文件
	FILE* pf = fopen("test.txt", "w");
	//使用文件
	fputs("Hello World", pf);
	//关闭文件
	fclose(pf);
	pf = NULL;
	return 0;
}

将程序运行后,该项目的路径下会生成一个test.txt的文本文件,其内容为"Hello World"
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
需要注意几点:

  1. 代码中打开的文件名为"test.txt",这个文件路径叫做相对路径,即相对于当前项目的路径,所以程序会将文件生成在该项目的当前目录下。如果要改成绝对路径可以用以下代码:"F:\code_record\code_learn\文件操作练习"
    当然这个只是我自己创建的项目的路径。你们创建的路径不同,绝对路径肯定也是不同的。

3.2 将文件中的内容读取到一个字符串中并且打印至屏幕。

刚刚我们已经生成文件test.txt 其内容为Hello World 我们现在重新操作文件,将这个字符串读取至内存中,并且打印在屏幕上。
代码如下:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int main()
{
	char str[20] = { 0 };
	//打开文件
	FILE* pf = fopen("test.txt", "r");
	//使用文件
	fgets(str, 20, pf);
	//关闭文件
	fclose(pf);
	pf = NULL;
	printf("%s", str);
	return 0;
}

程序运行结果:
在这里插入图片描述

3.3 随机读写的案例

在这里插入图片描述
还是同样的文件,同样的内容。我们现在需要从文件中提取"World"字符串并打印到屏幕。这里我们就可以使用到随机读取函数。
代码如下:

#include <stdio.h>
int main()
{
	char str[20] = { 0 };
	//打开文件
	FILE* pf = fopen("test.txt", "r");
	//使用文件
	fseek(pf, 6, SEEK_SET);//将文件指针从文件开始位置向后偏移6个字符
	fgets(str, 6, pf);
	//关闭文件
	fclose(pf);
	pf = NULL;
	printf("%s", str);
	return 0;
}

程序运行结果:
在这里插入图片描述

3.4 计算文件当前的偏移量

#include <stdio.h>
int main()
{
	char str[20] = { 0 };
	//打开文件
	FILE* pf = fopen("test.txt", "r");
	//使用文件
	fgets(str, 4, pf);
	int ret = ftell(pf);
	//关闭文件
	fclose(pf);
	pf = NULL;
	printf("%s\n", str);
	printf("%d\n", ret);
	return 0;
}

在这里插入图片描述

#include <stdio.h>
int main()
{
	char str[20] = { 0 };
	//打开文件
	FILE* pf = fopen("test.txt", "r");
	//使用文件
	char c1 = fgetc(pf);
	char c2 = fgetc(pf);
	int ret = ftell(pf);
	//关闭文件
	fclose(pf);
	pf = NULL;
	printf("%c\n", c1);
	printf("%c\n", c2);
	printf("%d\n", ret);
	return 0;
}

在这里插入图片描述

3.5 rewind函数的使用案例

还是同样的文件,我们这次要求读取两次"Hello World",就可以用rewind函数实现。
代码如下:

#include <stdio.h>
int main()
{
	char str1[20] = { 0 };
	char str2[20] = { 0 };
	//打开文件
	FILE* pf = fopen("test.txt", "r");
	//使用文件
	fgets(str1, 20, pf);
	rewind(pf);
	fgets(str2, 20, pf);
	//关闭文件
	fclose(pf);
	pf = NULL;
	printf("%s\n", str1);
	printf("%s\n", str2);
	return 0;
}

程序运行结果:
在这里插入图片描述

四. 文件读取结束的判定

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

  1. fgetc 判断是否为 EOF .
  2. fgets 判断返回值是否为 NULL .
  3. fscanf判断与scanf函数是一样的.
    二进制文件的读取结束判断,判断返回值是否小于实际要读的个数。
  4. fread判断返回值是否小于实际要读的个数.

总结

本篇博客主要介绍了一些常用的文件操作函数,但是已经足够改造我们的通讯录了。还有一些知识比如二进制文件和文件缓冲区。这些知识将会在之后补上。
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值