目录
一、前言
当我们向写好的通讯录程序中输入信息时,有时我们希望能保存输入的信息,不用每次打开这个程序都要重新输入,这时就可以用”文件“来保存。
什么是文件?文件就是保存在磁盘中的信息。存在内存中的信息是临时存储的,只有把它保存在磁盘中以文件的形式存储,才能持久保存。
二、文件的打开和关闭
知道了文件的作用,那么我们要怎么去建立一个文件并写入数据呢?
首先,我们要理解一个名词:文件指针。我们知道在缓冲文件系统中,假设我们要使用文件来保存信息,那么写入的信息是先保存在内存中的,积累一定量后,操作系统再把这些信息转入磁盘中的文件。
在内存中为了存储有关文件的信息(比如文件名、文件创建时间等),系统开辟了一个文件信息区(是一个结构体变量),文件指针就是该结构体类型的指针,指向打开的文件。
好了,知道了文件指针,我们来看看怎么操作一个文件,这时要用到两个函数:fopen和fclose。
FILE *fopen( const char *filename, const char *mode );
//fopen函数参数第一个是文件名,第二个是文件的打开方式,是只读还是只写或者读写
//fopen如果成功打开这个文件,就会返回该文件的指针,否则返回NULL
int fclose( FILE *stream );
//fclose的函数参数就是文件指针,意思就是关闭该文件指针指向的文件
//如果成功关闭文件,fclose返回0,反之返回NULL
讨论一下为什么要使用fclose?
在缓冲文件系统中,数据先保存在内存中的文件缓冲区,当文件缓冲区满了,操作系统再将数据保存到磁盘文件,而fclose也是把数据从文件缓冲区移到磁盘文件,在这种情况下,fclose和操作系统功能重叠,是不是可以不用fclose呢?
答案是不行!因为如果文件缓冲区还没满,操作系统还没来得及把数据移到磁盘,程序就结束了,就会造成数据丢失,所以一定不能忘记用了fopen,就一定要用fclose!
下面是fopen和fclose的使用:
#include<stdio.h>
int main()
{
//打开文件
FILE* pf = fopen("date.txt", "w");//"w"是文件的打开方式,以只写方式打开文件
if ( pf != NULL)
{
//写入数据
}
//关闭文件
fclose(pf);
return 0;
}
文件名:
文件名实际上是文件标识,包含文件路径、文件名、文件后缀,如c:\code\date.txt。
在上面的程序中,文件标识只有文件名和文件后缀,那就默认这个文件在当前源文件的目录下。
文件的打开方式:
"w" -- 只写,如果文件不存在,新建一个文件
"r" -- 只读,假设文件不存在就会报错
"a" -- 追加,如果文件不存在,新建一个文件
还有很多其他打开方式,例如读写--"w+"。
三、文件的读写
知道怎么打开关闭一个文件,我们来看看如何读写文件。文件的读写有顺序读写和随机读写。
1.文件的顺序读写
#include<stdio.h>
int main()
{
//打开文件
FILE* pf = fopen("date.txt", "w");//"w"是文件的打开方式,以只写方式打开文件
//char a = 'a';
if ( pf != NULL)
{
//写入数据
fputs("Hello world\n", pf);//把字符串写入文件
}
//关闭文件
fclose(pf);
return 0;
}
在运行以上程序后,date.txt文件中已被写入"Hello world",如果要再向文件中写入,就是直接接在"Hello world"后写;同样,从该文件中读取数据,也只能从第一个字符开始读取,这就是文件的顺序读写。
2.文件的随机读写
实现文件随机读写的函数:fseek, ftell, rewind。
int fseek( FILE *stream, long offset, int origin );
//令stream指向距离origin偏移量为offset位置处
origin 的可能取值:
SEEK_CUR
--文件指针当前位置
SEEK_END
--文件末尾
SEEK_SET
--文件开头
#include<stdio.h>
int main()
{
//打开文件
FILE* pf = fopen("date.txt", "w");
//char a = 'a';
if (pf != NULL)
{
//写入数据
fputs("Hello world", pf);
fseek( pf, 6, SEEK_SET);
fputs("everyone", pf);
//Hello world变成Hello everyone
}
//关闭文件
fclose(pf);
return 0;
}
long ftell( FILE *stream );
//用来得到文件指针stream当前位置相对于文件首位的偏移字节数
可以和fseek( pf, 0 ,SEEK_END)结合计算文件大小。
void rewind( FILE *stream );
//将文件指针stream重新指向文件开头
四、文件结束的判定
- 读取文本文件时,判断返回值是否为NULL或EOF;
- 读取二进制文件时,判断返回值是否小于实际读取的个数(如fread).
注意:在文件读取结束时,使用feof判断文件是因为读取失败结束,还是因为读到文件尾结束。