1.为什么使用文件
a是内存上的一块区域
如果程序退出,则内存回收,数据丢失了,再次运行就看不到上次的数据了
为了持久化保存,我们可以使用文件
2.文件是什么
磁盘上的文件是文件
在程序设计中,文件有两种:程序文件,数据文件
2.1程序文件
1)源文件(.c)
2)目标文件(windows环境后缀为.obj)
3)可执行程序(windows环境后缀为.exe)
2.2数据文件(这里讨论的就是这种)
文件的内容不一定是程序,而是程序运行时读写的数据
如:程序运行需要从中读取数据的文件,或者输出内容的文件
以前所处理的数据的输入输出都是以终端为对象的(从终端的键盘输入数据),运行结果显示到显示器上
我们也会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理的就是磁盘上的文件
2.3文件名
文件名就是文件标识
文件名包含三部分:文件路径+文件名主干+文件后缀
eg. c:\code\text.txt
3.根据数据的形式,数据文件被称为文本文件或者二进制文件
二进制文件:
数据在内存中以二进制的形式存储,不加转换地输出到外存
文本文件:
如果要求在外存上以ASCII码的形式存储,就需要在存储前转换
以ASCII字符的形式存储的文件就是文本文件
一个数据在内存中的存储
字符一律使用ASCII形式存储
数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储
测试:
4.文件的打开和关闭
4.1流
流包含各种流,标准流只是一种
我们可以把"流"想象成流淌着字符的河
C程序`针对文件,画面,键盘等的数据输入输出操作都是通过流操作的
一般情况下,我们要想向流里写数据,或者从流中读取数据,都是要打开流然后操作
4.2标准流
我们从键盘输入数据,向屏幕上输出数据并没有打开流的原因是因为C语言程序在启动的时候默认打开了三个流
1)stdin - 标准输入流,在大多数的环境中从键盘输入,scanf函数就是从标准流中读取数据
2)stdout - 标准输出流,大多数的环境中输出至显示器界面,printf函数就是将信息输出到标准输出流中
3)stderr - 标准错误流,大多数环境中输出到显示器界面
默认打开了这三个流,我们使用scanf,printf等函数就可以直接进行输入输出操作
三个流的类型是:FILE*,成为文件指针(痛过文件指针找到流,通过流的操作再操作对应的外部设备)
三个流就是指向文件信息区的指针
scanf读取数据时并没有打开流,直接在标准输入流中读取数据
printf直接输出信息输出到stdout对应的流里面
对于程序来说,文件,光盘,U盘等这些是外部设备
4.3文件指针
缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”
每个被使用的文件都在文件中开辟了一个相应的文件信息区,用来存放文件的相关信息(文件的名字,文件状态及文件当前的位置),这些信息是保存在一个结构体变量中的,该结构体类型是由系统声明的
每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,使用者不用关系细节
一般都是通过一个FILE的指针来维护这个FILE结构的变量
文件信息区和将要操作的文件进行关联,想要实现这个就要拿到指向文件信息区的这个指针
FILE* pf;//文件指针变量
pf是一个指向FILE类型数据的指针变量,可以使pf指向某个文件的文件信息区(是一个结构体变量),通过该文件信息区中的信息就能访问该文件,也就是说通过文件指针变量能够间接找到与它关联的文件
文件在硬盘里存放 文件信息区在内存存放
4.4 文件的打开和关闭
文件在读写之前应该先打开文件,在使用结束之后应该关闭文件
在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指针和文件的关系
打开文件
fopen
FILE* fopen ( const char * filename ,const char * mode);
文件名 文件的打开方式
mode:
文件的使用方式: 含义 : 如果指定文件不存在:
如果这个文件不存在,则会新建一个文件,如果存在,他会把文件里面的内容清空
运行后
关闭文件
fclose
int fclose ( FILE * stream);
相对:
5.文件的读和写
以读的形式打开文件,就只能读
以写的形式打开文件,就只能写
stdin -- 标准输入流
读的形式打开文件--得到的是一个文件的输入流
stdout
写的形式打开文件--得到的是文件的输出流
文件的顺序读写
函数名 功能 适用于
fputc(将字符写到流里面去)
fgetc
fputs
把一个字符串写到文件里面去(写的时候要自己写'\0',不然文件里面的内容都是在一行上的)
首字符的地址
fgets
从FILE*指向的文件流里去读字符串
区分放进去的还是不放进去的
实际上真正读的是n-1个字符再加上'\0'
如果修改文件内容,在字符串中添加'\0',则读的时候遇到'\0'就不读了(但是'\0'还是会有),也不会再读下一行(即使没有达到字符个数)
解释:如果num=10;
这一行超过10个字符则读九个再加一个'\0',如果不超过9个就换行了,则读到'\0'就停下来了
fwrite
size_t fwrite ( const void * ptr , size_t size ,size_t count , FILE * stream ) ;
将ptr中count个大小为size个字节(一个元素的大小)的数据写到文件中
(在流里面写count个size大小的数据到ptr指向的空间里面)
fread
size_t fread ( void * ptr , size_t size , size_t count , FILE * stream ) ;
成功读取几个元素返回几个;小于count则为最后一次了
从文件中读取count个大小为size个字节的数据,存放在ptr指向的空间中
对比一组函数
scanf/fscanf/sscanf
scanf 针对标准输入流的格式化输入函数
int scanf ( const char * format, ... ) ; 可变参数列表
fscanf 针对所有输入流的格式化输入函数
int fscanf ( FILE * stream,const char * format,... ) ;
sscanf 将格式化的数据转换成字符串
int sscanf ( const char * s, const char * format ,... ) ;
printf/fprintf/sprintf
printf 针对标准输出流得格式化输出函数
int printf ( const char * format , ... ) ;
fprintf 针对所有输出流的格式化输出
int fprintf ( FILE * stream , const char * format , ... ) ;
sprintf 是从字符串中提取格式化的数据
可以理解为,将字符串转成格式化的数据
int sprintf ( char * str , const char * format ,... ) ;
6.文件的随机读写
fseek
根据文件指针的位置和偏移量来定位文件指针(根据需要调整指针的位置)
int fseek ( FILE * stream , long int offset , int origin ) ;
偏移量 起始位置
SEEK_SET 文件的起始位置
SEEK_CUR 文件指针当前的位置
SEEK_END 文件的末尾
ftell
返回文件指针相对于起始位置的偏移量
long int ftell ( FILE * stream ) ;
rewind
让文件指针的位置回到文件的起始位置
拷贝文件
7.文件读取结束的判定
EOF -- end of file 文件结束的标志
以为feof函数是用来判断文件是否结束的
但是并不是
在读取文件的过程中,有可能读取文件错误
原因:
1.遇到文件末尾
2.遇到错误
文本文件:
fgetc 读取失败会返回EOF
fgets 读取失败或遇到文件末尾会返回空指针
二进制文件:
fread 判断返回值是否小于实际要读的个数
小于count则为最后一次了
8.文件缓冲区
所谓缓冲文件系统是指系统自动地在内存中为每一个正在使用的文件开辟一块“文件缓冲区”,
从内存向磁盘输出数据先送到内存中的缓冲区,装满缓冲区后才一起送到磁盘上
如果从磁盘向计算机读入数据,则从磁盘文件中读取数据输入到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)
缓冲区的大小根据C编译系统决定
结论:因为有缓冲区的存在,C语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文件。如果不做,可能导致读写文件的问题