一文带你搞清C语言文件操作

根据数据组织形式,文件分为文本文件或二进制文件

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

如果在外存上要以ASCII码形式存储,则需要在存储前转换,这种方式存储的文件就是文本文件

一、流和标准流

1、流

流是一个抽象的概念。我们需要从外部获取数据,也需要将数据输出到各种外部设备,不同设备的输入输出方式各不相同,因此我们抽象出流的概念。 我们可以通过流来进行各种输入输出操作。

一般情况,我们要向流中写数据,和从其中读取数据,都是要先打开流,然后操作。

2、标准流

对于C语言程序,在其启动的时候,会默认打开三个流:

stdin-标准输入流,在大多数时候从键盘输入,例如scanf函数就是从标准输入流中读取数据

stdout-标准输出流,大多数时候输出到显示器界面,例如printf函数就是将信息输出到标准输出流

stderr-标准错误流,大多数时候将错误输出到显示器界面

这三个流的类型是FILE* 即文件指针,在C语言中我们通过文件指针来维护流的各种操作

二、文件的打开和关闭

1、文件指针

每个被使用的文件都会在内存中开辟一个对应的文件信息区,用来存放文件的相关变量,如:文件名,文件状态,文件位置等。这些信息保存在一个结构体类型的变量中,结构体类型名位FILE

那么FILE*指针就可以指向这个FILE结构的变量,即指向该文件的文件信息区,通过文件信息区我们就可以访问该文件。

2、文件打开与关闭

我们使用fopen来打开文件,fclose关闭文件

打开文件之前,我们需要先创建FILE* 指针变量p来指向这个文件

FILE* P
(1)、fopen

观察其参数,第一个参数是文件名,其实也就是文件路径,第二个参数是打开方式

我们先来看一个简单的打开

在运行过后,我们发现目录底下确实多出来一个text.txt的文件,只不过我们现在还没有往里面写东西,里面内容是空的

如果打开成功,fopen会返回文件信息区的起始地址,如果打开失败,会返回NULL

因此在打开后我们需要加上一个判断

(2)、打开方式

我们上例中使用的打开方式是”w“ 因为我们原来并没有text.txt这个文件,因此这种方式打开后会创建一个新的文件,同时我们可以往里面写东西。

简单来说,r只能读不能写,并且不能创建文件,w覆盖写,会清除掉文件中原本内容,a追加写,会从文本内容末尾追加继续写,w和a都可以创建文件。


(3)、fclose

关闭文件用到fclose

对于任意文件我们进行操作都要打开和关闭,在操作完文件后,一定要记得关闭文件

关闭文件后,p所指向的空间就不能被使用,此时p为野指针,要及时将p置为NULL

三、文件的读写

1、顺序读写

这是一些顺序读写的函数,我们来一一使用一下看

(1)、fputc

fputc是用来向文件中写入字符的,一次可以写入一个字符

其第一个参数为要写入的字符,第二个参数为文件指针

程序运行之后我们发现果然在文件中写入了xyz,那么我们这里直接使用循环打印从a到z

如图,我们正确使用了fputc这个函数

当然,上面说了fputc使用与所有输出流,那么我们就可以通过stdout这个输出流打印到屏幕上

程序一运行,可以看到直接将a到z打印在屏幕上

(2)、fgetc

其参数为一个流

如果读取成功,会返回读到字符的ASCII码,如果读取失败或者读取结束,会返回一个EOF

我们可以借用上面的例子,使用fgetc得到a至z

如图所示,也能成功办到,当然如果我们把fgetc中的输入流改为stdin就是从键盘上读取信息了,这点跟scanf功能相似

(3)、fputs

一次可以写入一串字符 第一个参数为要写的内容,第二个参数为输出流

如果成功,返回一个非负值,如果失败,返回EOF

如图我们写了两串字符串,

但是却发现其写在一行上了,如果要换行,第一次写的时候最后加上\n即可,此处不再赘述

(4)、fgets

第一个参数为指向字符数组的指针,读到的会被拷贝,存储num-1个字符,,最后一个字符得存放\0,最后一个参数是输入流

我们调试后发现,arr中拷贝了4个字符过去 

注意:如果写入的文件中有\n等,也会算作一个字符读走 fgets一次读一行

如果想要每行全部读完

利用while循环读取结束或失败后会返回一个NULL 从而打印出全部内容

(5)、fprintf

将格式化的数据写入到流中,

其相比printf 只有第一个参数不一样

如果按照printf来打印,那么就是直接打印到屏幕上,这里fprintf前面多了给参数,意思就是将这些数据格式化打印到所指向的文件中。

(6)、fscanf

既然上面fprintf是向文件中写入格式化的数据,那么fscanf自然就是从文件中读出格式化的数据喽,废话不多说,直接来看

我们num score arr的值都是未定义的从文件中读出来后,就可以直接打印出值

注意:如果将fscanf中的输入流改为stdin,将fprintf中的输出流改为stdout,则这两个函数就与scanf和printf一样了

(7)、fread与fwrite

用于二进制文件的读和写

ptr指向了要写的数据 size是要写的一个元素的大小,count是写的元素的个数,最后一个是流

其参数与fwrite几乎一模一样

如果想读几个值那么size_t count就设置为几 当然也可以一个一个读,即&arr[i]或arr+i

fread的返回值是成功读取到的个数,若其返回值小于要求读取的个数,这就是最后一次读取

2、补充:sscanf与sprintf
(1)、sprintf

将格式化的数据转换成一个字符串

注意:此时我们printf是按字符串形式打印的,即此时打印出的str是字符串,也就是将三个信息整合成了一个字符串

(2)、sscanf

从字符串中提取格式化的数据

3、随机读写
(1)、fseek

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

第一个参数为流,第二个为偏移量,第三个为起始位置

origin起始位置只要三个取值,即文件起始位置,文件当前位置,文件末尾

我们现在data.txt文件中写入abcdef

比如我们先读到a,接下来我们想读到d 那么设定当前光标位置为起始位置,,当前光标指向b的位置,那么其向后偏移两个单位后,就指向d,同理可根据不同的起始位置确定不同的偏移量得到d

当然,偏移量也可为负值,即向前偏移,适用于位置为文件末尾时读前面的数据等等。

(2)、ftell

ftell函数可以告诉我们文件当前光标相对于起始位置的偏移量

在上例中我们读完d后光标指向e 那么e相对于起始位置a的偏移量,我们就可以用ftell函数来算

如图,得到正确的偏移量,我们可以通过这个函数随时得到现在读到文件的哪个位置了

(3)、rewind

将文件指针的位置改回到文件的起始位置

在上例中,我们已经读到了e 如果rewind函数回到起始位置后,再读一次,又会读到a

来看示例:

说明rewind之后文件指针成功回到了文件的起始位置

4、文件读取结束的判定
(1)、文本文件

对于⽂本⽂件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )

(2)、二进制文件

 ⼆进制⽂件的读取结束判断,判断返回值是否⼩于实际要读的个数

(3)、被错误使用的feof

feof 的作⽤是:当⽂件读取结束的时候,判断是读取结束的原因是否是:遇到⽂件尾结束。

我们已经知道文件读取结束了,使用feof来判断读取结束的原因是否是这样,而不能使用feof来判断文件读取是否结束

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值