一、为什么要使用文件
如果没有⽂件,我们写的程序的数据是存储在电脑的内存中,如果程序退出,内存回收,数据就丢失 了,等再次运⾏程序,是看不到上次程序的数据的,如果要将数据进⾏持久化的保存,我们可以使⽤ ⽂件。
二、什么是文件
磁盘(硬盘)上的⽂件是⽂件。
但是在程序设计中,我们⼀般谈的⽂件有两种:程序⽂件、数据⽂件(从⽂件功能的⻆度来分类 的)。
程序文件:
程序⽂件包括源程序⽂件(后缀为.c),⽬标⽂件(windows环境后缀为.obj),可执⾏程序(windows 环境后缀为.exe)。
数据文件:
⽂件的内容不⼀定是程序,⽽是程序运⾏时读写的数据,⽐如程序运⾏需要从中读取数据的⽂件,或 者输出内容的⽂件
本文主要讨论数据文件。
根据数据的组织形式,数据⽂件被称为文本文件或者二进制文件
三、二进制文件和文本文件
数据在内存中以⼆进制的形式存储,如果不加转换的输出到外存的⽂件中,就是⼆进制⽂件。
如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的⽂件就是文本文件。
⼀个数据在⽂件中是怎么存储的呢?
字符⼀律以ASCII形式存储,数值型数据既可以⽤ASCII形式存储,也可以使⽤⼆进制形式存储。
举个栗子:如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占⽤5个字节(每个字符⼀个字节),⽽ ⼆进制形式输出,则在磁盘上只占4个字节
四、文件的打开和关闭
4.1 流
我们程序的数据需要输出到各种外部设备,也需要从外部设备获取数据,不同的外部设备的输⼊输出 操作各不相同,为了⽅便程序员对各种设备进⾏⽅便的操作,我们抽象出了流的概念,我们可以把流 想象成流淌着字符的河
C程序针对⽂件、画⾯、键盘等的数据输⼊输出操作都是通过流操作的。 比特就业课 ⼀般情况下,我们要想向流⾥写数据,或者从流中读取数据,都是要打开流,然后操作
4.2 标准流
那为什么我们从键盘输⼊数据,向屏幕上输出数据,并没有打开流呢?
因为C语⾔程序在启动的时候,默认打开了3个流:
- stdin-标准输⼊流,在⼤多数的环境中从键盘输⼊,scanf函数就是从标准输⼊流中读取数据
- stdout-标准输出流,⼤多数的环境中输出⾄显⽰器界⾯,printf函数就是将信息输出到标准输出流中
- stderr-标准错误流,⼤多数环境中输出到显⽰器界⾯
这是默认打开了这三个流,我们使⽤scanf、printf等函数就可以直接进⾏输⼊输出操作的。
4.3 文件指针
缓冲⽂件系统中,关键的概念是“⽂件类型指针”,简称“⽂件指针”。
每个被使⽤的⽂件都在内存中开辟了⼀个相应的⽂件信息区,⽤来存放⽂件的相关信息(如⽂件的名 字,⽂件状态及⽂件当前的位置等)。这些信息是保存在⼀个结构体变量中的。该结构体类型是由系 统声明的,取名FILE.
每当打开⼀个⽂件的时候,系统会根据⽂件的情况⾃动创建⼀个FILE结构的变量,并填充其中的信 息,⼀般都是通过⼀个FILE的指针来维护这个FILE结构的变量,这样使⽤起来更加⽅便。
下⾯我们可以创建⼀个FILE*的指针变量:
FILE* pf;// ⽂件指针变量
定义pf是⼀个指向FILE类型数据的指针变量。可以使pf指向某个⽂件的⽂件信息区(是⼀个结构体变 量)。通过该⽂件信息区中的信息就能够访问该⽂件。也就是说,通过⽂件指针变量能够间接找到与 它关联的⽂件
4.4 文件的打开和关闭
⽂件在读写之前应该先打开⽂件,在使⽤结束之后应该关闭⽂件
ANSI C规定使⽤ fopen 函数来打开⽂件, fclose 来关闭⽂件
//打开⽂件
FILE * fopen ( const char * filename, const char * mode );
//关闭⽂件
int fclose ( FILE * stream );
mode表⽰⽂件的打开模式,下⾯都是⽂件的打开模式:
举个例子:
五、文件的顺序读写
5.1顺序读写函数介绍
1)fputc(): 用于向文件中写入一个字符。 函数原型为:int fputc(int c, FILE *stream);
c: 要写入的字符的ASCII码。
stream: 指向要写入的文件的指针。
返回值为写入成功的字符的ASCII码,若写入失败则返回EOF。
2)fgetc(): 用于从文件中读取一个字符。 函数原型为:int fgetc(FILE *stream);
.stream: 指向要读取的文件的指针。
返回值为读取到的字符的ASCII码,若到达文件结尾则返回EOF
优化一下:
3)fputs(): 用于向文件中写入一个字符串。 函数原型为:int fputs(const char *str, FILE *stream);
str: 要写入的字符串。
stream: 指向要写入的文件的指针。
返回值为写入成功的非负整数,若写入失败则返回EOF。
4)fgets(): 用于从文件中读取一行字符串。 函数原型为:char *fgets(char *str, int size, FILE *stream);
str: 字符串指针,用于存储读取到的字符串。
size: 最多读取的字符数,包括结尾的'\0'。
stream: 指向要读取的文件的指针。
返回值为成功读取到字符串的指针,若到达文件结尾则返回NULL。
5)fprintf
函数原型为:int fprintf ( FILE * stream, const char * format, ... );
以格式化的形式向流(stream)中输出数据
成功后,将返回写入的字符总数。
如果发生写入错误,则设置错误指示器(ferror)并返回负数。
6)fscanf
int fscanf ( FILE * stream, const char * format, ... );
以格式化的形式从流(stream)中读取数据。
成功后,该函数返回成功填充的参数列表的项数。此计数可以与预期的项目数匹配,也可以由于匹配失败、读取错误或文件末尾的到达而减少(甚至为零)。
如果发生读取错误或在读取时到达文件末尾,则会设置正确的指示器(feof 或 ferror)。并且,如果在成功读取任何数据之前发生任一情况,则返回 EOF。
5.2对比函数
scanf / fscanf / sscanf
printf / fprintf / sprintf
scanf:int scanf ( const char * format, ... );
fscanf:int fscanf ( FILE * stream, const char * format, ... );
sscanf:int sscanf ( const char * s, const char * format, ...);
scanf - 从标准输出流上读取格式化的数据
fscanf - 从指定输出流上读取格式化的数据
sscanf - 从字符串中读取格式化的数据
printf:int printf ( const char * format, ... );
fscanf:int fprintf ( FILE * stream, const char * format, ... );
sscanf:int sprintf ( char * str, const char * format, ... );
printf - 把数据以格式化的形式打印在标准输出流上
fprintf - 把数据以格式化的形式打印在指定输出流上
sprintf - 把格式化的数据转换成字符串
5.3 fwrite
函数原型:size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );
以二进制的形式将ptr存储的数据写入流中,一共写入count个元素,每个元素的大小为size字节。
返回成功写入的元素总数。
如果此数字与
count
参数不同,则写入错误阻止函数完成。在这种情况下,将为流设置错误指示器(ferror)。如果
size
或count
为零,则该函数返回零,错误指示器保持不变。
5.3 fread
函数原型:size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );
以二进制的形式从流中读取count个元素,每个元素的大小为size字节,并将它们存储在 ptr 指定的内存块中。
返回成功读取的元素总数。
如果此数字与count参数不同,则表示读取时发生读取错误或到达文件末尾。在这两种情况下,都会设置正确的指标,可以分别用 ferror 和 feof 进行检查。
如果
size
或count
为零,则该函数返回零,并且流状态和 ptr 指向的内容保持不变。
六、文件的随机读写
6.1 fseek
函数原型:int fseek ( FILE * stream, long int offset, int origin );
根据文件位置和偏移量来定位文件指针(⽂件内容的光标)。
offset
为偏移量
origin
为起始位置,有三种取值:
SEEK_SET:文件起始位置
SEEK_CUR:文件指针的当前位置
SEEK_END:文件末尾
6.2 ftell
函数原型:long int ftell ( FILE * stream );
返回⽂件指针相对于起始位置的偏移量
6.3 rewind
函数原型:void rewind ( FILE * stream );
让⽂件指针的位置回到⽂件的起始位置
七、文件读取结束判定
7.1 被错误使⽤的feof
牢记:在文件读取的过程中,不能使用feof
函数的返回值直接来判断文件是否结束
feof的作⽤是:当⽂件读取结束的时候,判断是读取结束的原因是否是:遇到⽂件尾结束
文件读取结束了,但是是什么原因让读取结束的呢?
feof:读到了文件末尾
ferror:读取的时候发生了错误
文本文件读取:
- fgetc 判断是否为 EOF .
- fgets 判断返回值是否为 NULL .
fgetc - 如果读取正常,返回的是读取到字符的ASCII码值
如果读取的过程中遇到文件末尾,或者发生错误就返回EOF
fgets - 如果读取正常,返回的是存储读取到的字符数组的地址
如果读取的过程中遇到文件末尾,或者发生错误,返回NULL
二进制文本读取:
判断返回值是否⼩于实际要读的个数。
举个栗子:
本文到这里就结束了,如有问题欢迎指导!