根据数据组织形式,文件分为文本文件或二进制文件
在内存中以二进制的形式存储,不加转换输出到外存的文件中,就是二进制文件
如果在外存上要以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来判断文件读取是否结束
标签:文件,一文,位置,指针,搞清,参数,C语言,我们,读取 From: https://blog.csdn.net/L_142190687/article/details/142630393