C语言文件操作

目录

1. 为什么使用文件

2. 文件介绍

2.1.程序文件

2.2 数据文件

2.3 文件名

3. 文件的打开和关闭

3.1 流

3.2 文件指针

3.3 文本文件和二进制文件

3.4 打开和关闭操作

3.4.1打开文件 

3.4.2 关闭文件

4. 文件的顺序读写

4.1 文件的顺序读写

4.2 对比一组函数

5. 文件的随机读写

5.1 fseek

5.2 ftell

5.3 rewind

6. 文件读取结束的判定

6.1 错误使用的feof函数


1. 为什么使用文件

假设我们编写了一段程序,比方说,我们的通讯录,在出了main函数的时候,所有数据都会被清

空.但是这显然是不合理的,假设通讯录存了100个人的数据,难道下次我们重新运行程序的时候,

又要重新输入100个人的信息吗?

所以,我们就需要一个方法,把数据保存起来,即便出了main函数,它依旧存在.

常见的方法有:

1.把数据存放在磁盘文件  2.存放到数据库

而我们今天介绍的,就是把数据保存到文件中,存放在磁盘里.

2. 文件介绍

文件一般分为两个大类,程序文件和数据文件,下面我们就分别对它们进行介绍.

2.1.程序文件

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

 

 像上面图片那些,都是程序文件,一般我们用IDE写完程序后保存,在磁盘中,根据保存路径,找

到的文件就是我们的程序文件.

2.2 数据文件

文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,
或者输出内容的文件.
最常见的像我们,在电脑自带的记事本上用键盘输入一些数据,然后选择另存为.

得到的txt文件就是数据文件,它的内容也未必和程序有关.

2.3 文件名

一个文件要有一个唯一的文件标识,以便用户识别和引用.
文件名包含 3 部分:文件路径 + 文件名主干 + 文件后缀
例如: D :\code\test.txt
加斜杆的就是文件的路径,也就是存放在哪个地方.
test就是文件名主干,.txt就是文件后缀.

3. 文件的打开和关闭

3.1 流

流(stream)这个概念非常生动形象,一个个数据相当于一个个水滴,当一堆数据进行传递的时候,便形成了流

它可以是源,我们常说的屏幕就是一个流,称为stdout,标准输出流.

它也可以是输出的目的地,比如我们的键盘也是一个流,称为stdin,标准输入流.

而对于任何C程序,只要运行起来,都会默认打开下面三个流.

3.2 文件指针

每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息
(如文件的名字,文件状态及文件当前的位置等).
这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明(在<stdio.h>中)的,取名为
FILE.
//vs 2013中对FILE结构体的声明
struct _iobuf {
	char* _ptr;
	int   _cnt;
	char* _base;
	int   _flag;
	int   _file;
	int   _charbuf;
	int   _bufsiz;
	char* _tmpfname;
};
typedef struct _iobuf FILE;

而C程序中对流的访问就是通过指针来实现的,此指针类型为FILE *

一个文件就对应一块结构体空间,我们创建不同FILE *类型指针指向不同的空间,维护起来也就更

加方便.(通过文件指针变量能够找到与它关联的文件)

3.3 文本文件和二进制文件

<stdio.h>支持两种类型的数据文件(根据数据组织形式),一种是文本文件,另一种是二进制文件.

在文本文件中,字节表示字符,程序员是可以看得懂,并且对它进行检查和编辑.比方说C程序的源

代码就是用文本文件进行存储的.

但是也有二进制文件进行存储的,也就是用二进制的方式进行存储数据,这我们往往是看不懂的,

需要"翻译"的工具才能看得懂.

比如存在一个二进制文件,里面放了一堆数据,假设我用记事本打开,记事本是没有“翻译”功能

的,因此,你打开文件,只会看到一堆乱码.

举一个具体例子,假设考虑在文本文件中存入32767这个数字

如果是按照文本文件进行存储,则32767将会被看成是‘3’,‘2’,‘7’,‘6’,‘7’五个字符,然后分别存储起来.

但假设按照二进制方式进行存储.对应可能只是两个字节,而你假设你用记事本打开,此时依旧是看

不懂的,需要vs提供二进制“翻译”二进制文件的功能.

 

3.4 打开和关闭操作

对于C语言文件,我们一般就按照以上三个步骤进行操作,下面介绍打开和关闭两个操作.

ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件.

3.4.1打开文件 

fopen函数需要两个参数
一个是filename,类型是char*,也就是含有要打开文件名的字符串
上述操作就是打开我们先前创建的test1.txt(记事本文件)
还可以是文件路径(同样包含文件名)

不过要小心,目录分隔符\前面要加上\,否则我们直到存在转义字符这样一个东西,\t代表的制表符可不要出现在我们含文件名的字符串中.

为了方便起见,还可以这样书写.

在windows,会把/看作是目录分隔符. 

另一个是打开的模式mode.
下面是文本文件的模式字符串.

 

像我们这个例子里的“r”(read),代表的就是打开输入操作的文件,该文件必须存在.

如果是"w"(write),代表的就是往文件里面写入数据(输出),如果原本存在的文件,就会覆盖原

来的数据,如果不存在,则会创建一个新的空文件,然后再进行输出.

如果是二进制文件的模式字符串,需要在后面加上b,表示binary,也就是二进制的意思.

在无法打开文件的时候,比方说文件不存在,文件位置不对,无访问权限等等,fopen会返回一个空

指针.因此,为了程序不会出现意外奔溃,我们都要养成一个习惯,对fopen返回值,判断它是否为

空.

3.4.2 关闭文件

 

 fclose只需要一个参数,就是我们指定要关闭的流的 FILE 对象的指针.

 同时,和动态分配一样,关闭文件后,空间被释放,而指针并不为置为NULL,需要程序员手动进

行操作.

 

4. 文件的顺序读写

4.1 文件的顺序读写

在从前,我们都是利用scanf,printf进行输入和输出数据.

而实际上,文件的读写,和之前也是类似的,只不过文件成为了新的输入和输出流.

读和写依旧是相同的,唯一的区别,只是流发生了改变,现在不再是标准输入输出流,而是我们

本章的主角——文件.

 这里我们不会一一进行介绍,有需要直接取cplusplus.com搜索相应功能即可.

这里以fgets函数为例子,进行相应的说明.

在网站上,我们可以了解到fgets具体功能,它需要三个参数

一个是str,其实就是我们用来存放文件数据字符的字符数组地址

一个是num,复制到 字符数组 中最大字符数(包括终止空字符)

最后一个是我们的流,也就是文件指针.

假设我们在记事本中存下我们的字符,创建一个字符数组str,用来存放我们从文件中读到的数据.

那按照上面操作,直接使用就好.

4.2 对比一组函数

scanf/printf函数我们先前已经了解过它的使用,两个函数分别是格式化输入和输出的函数.这里不

再多介绍. 

fscanf/fprintf函数在此基础上,又更加升级了一步,scanf/printf函数是用于标准输入输出流的,

fscanf/fprintf适用于所有输入输出流(也就是文件也可以,而scanf/printf函数则做不到的)

由函数声明,我们也可以看出来这点,fscanf函数所有参数和scanf函数完全一致,就多了一个

stream的FILE指针,指定我们从什么流进行输入数据.

sscanf/sprintf函数则和上面两组函数不同,功能上也有较大的差别.

sscanf函数是从一个字符串中格式化读入数据.

 

比方说,我有一个字符数组s,里面存放了字符串,然后我想把它们分割,然后格式化录入到不同变量或者字符数组中,使用的就是这个函数.

值得注意,在下面这段程序中,我并不想录入is这个字符串,又没有创建相应字符数组存储起来

此时我在格式中,加入了%*s,*代表着赋值屏蔽,读入此数据项和格式串进行匹配,但不会把它赋值给对象,用在这里代表越过了is这个字符串,往后面进行匹配我的%d.

 sprintf函数是把格式化的数据转化成字符串.

 和printf函数操作也是类似,不过,此时是格式化的将数据转化成字符串,存储到一个字符数组str

里面.

由网站给出的例子也可以看出,转化成字符串的时候,会给它末尾自动补上‘\0’

返回值则是返回写入的字符总数.此计数不包括自动追加到字符串末尾的其他空字符.

(指成功的情况,不成功,返回一个负数).

5. 文件的随机读写

有时候我们并不希望一个一个读取或者输出文件中的数据,这时候,就需要我们随机读写函数进行辅助.

5.1 fseek

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

fseek三个参数,FILE指针,偏移量,以及初始设定模式.

首先介绍初始设定模式,有下面三种情况.文件开头,文件指针指向的当前位置,以及文件结尾.

 

有了标准,也就是初始设定模式,一个标杆,我们就可以给定偏移量,指定文件指针指向文件中的任意位置.

比如下面这段程序,在fputs函数调用完后,文件指针pFile应该指向文件的末尾,但我们对它用fseek函数重新移动到开头偏移9个字节的位置,此时再fputs则会覆盖原来的数据,apple变为sample.

 

5.2 ftell

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

不多介绍,给定文件指针,返回文件指针相对于起始位置的偏移量. 

5.3 rewind

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

实际上,调用rewind函数和fseek(fp,0,SEEK_SET)没有什么区别,唯一区别,可能就是rewind函数不返回参数,但会为pf清楚错误指示器.

当然,上述函数也有很多细节值得注意,比方说《C程序现代设计》一书中提到的.

6. 文件读取结束的判定

6.1 错误使用的feof函数

feof函数的功能就是检查是否设置了end-of-file indicator.

那什么是end-of-file indicator呢?

我们看一下书上的具体描述 

那假设我打开一个文件,里面没有放任何数据,此时刚打开文件,指示器都是清空的,那此时我们

可以用feof函数判断是否结束吗?显然是不可以的.

从实际上,里面没有放任何数据,此时文件已经结束.

但是由于此时还没有创建文件末尾指示器,feof函数根本就不会返回非零值,表示文件已经结束.

 

因此, 在文件读取过程中,不能用feof函数的返回值直接用来判断文件的是否结束 .
而是 应用于当文件读取结束的时候,判断是读取失败结束,还是遇到文件尾结束,需要配合其它
像fget,fread等等函数的返回值来一起使用的.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值