1、文件基础 文件指存储在外部介质上的数据集合。
常见的文件如下:
为了简化各种设备的操作,使用户不必区分各种设备之间的区别,操作系统 把各种设备都统一作为文件来处理。从操作系统的角度看,每一个输入输出设备 都是一个文件。其中键盘是标准输入设备,其文件标识符为”stdin”,屏幕是标 准输出设备,其文件标识符为”stdout”。
数据如流水一样从一处流向另一处,因此常将输入输出的数据称为数据流。
数据从文件(外存)流向内存称为输入流,数据从内存流向文件(外存)称为输出流。
文件名
文件要有一个唯一的文件标识,以便用户识别和使用。
文件标识包括三部分:文件路径+文件名主干+文件后缀名。如下所示:
文件后缀名的作用为关联操作系统打开该类型文件的默认应用程序。上图 mp3 文件默认关联的就是 QQ 音乐。当然这个是可以修改的。
文件的分类根据数据的组织形式,文件可以分为二进制文件和文本文件。
二进制文件:数据在内存中是以二进制形式存储的,如果不加转换直接保存 到文件中,就是二进制文件。
常见的二进制文件有图片文件,音频文件,视频文件,可执行程序文件等。这 些文件都不能利用记事本直接查看,必须依赖特定应用程序解析,例如 mp3 音频 文件必须通过 mp3 播放器才能播放。
一个数据在文件中如何存储呢?例如数字 123456。
如果在文本文件中则存储字符 1,字符 2,字符 3,字符 4,字符 5,字符 6 的编 码共 6 字节。
如果在二进制文件中,数字 123456 为整型占用 4 字节。存储如下:
二进制文件不需要转换,读写时更节约时间,相比文本文件也更节约空间,所 以二进制文件使用最广泛。
2、文件操作
打开与关闭文件
文件指针也称文件类型指针,用于保存每个打开的文件信息,同一时间系统 中打开的所有文件的文件指针都是独一无二的,文件指针可以看作是文件操作的 唯一标识。在 C 代码中用”FILE *”表示。
FILE *fopen(const char *filename,const char *mode);
fopen 函数:创建或打开文件。其中参数
filename:需要创建或者打开的文件名;
mode:打开文件的方式。常见的有读”r”,写”w”,二进制读”rb”,二进制 写”wb”等,其它方式请查看帮助手册。
注意”w”和”wb”打开的文件如果已经存在则清空原文件的数据再打开, 如果文件不存在则创建一个新文件并打开。”r”和”rb”打开文件时该文件必 须存在否则打开失败。
返回值:打开成功则为打开文件的文件指针,失败则为 NULL。
文件打开后,可以通过文件指针操作该文件。文件操作结束记得关闭文件,否 则会出现内存泄漏。
int fclose(FILE *stream);
fclose 函数:用于关闭打开的文件。参数
stream:需要关闭的文件指针。
int main()
{
FILE *fw = fopen("D:\\1.txt","w");
assert(fw != NULL);//断言文件打开成功
//文件操作过程省略......
fclose(fw); //关闭文件
return 0;
}
顺序读,写文件 读写操作主要通过 fread 和 fwrite 两个函数完成,函数原型如下:
size_t fread(void *buffer,size_t size,size_t count,FILE *stream);
fread 函数:用于从文件中读取数据,其中参数为:
buffer:存放从文件中读取的数据; size:每个单元数据的字节数;
count:总共读取多少个单元数据; stream:读取数据的文件指针。
返回值:读取成功的单元数据个数,非常重要。如果这个值少于 count 则可以判 断文件已经全部读完。
size_t fwrite(const void*buffer,size_t size,size_t count,FILE *stream);
fwrite 函数:用于向文件写数据,其中参数为:
buffer:写入文件中的数据;
size:每个单元数据的字节数;
count:总共写入多少个单元数据;
stream:写入的文件指针。
返回值:写入成功的单元数据个数,不重要。
读写文本文件:
//往文件写入文本数据
int main()
{
FILE *fw = fopen("1.txt","w"); //创建或打开一个新文件
assert(fw != NULL);
char *str = "欢迎来图论学习"; //写入文件的数据
fwrite(str,sizeof(char),strlen(str),fw);//写数据
fclose(fw); //关闭文件
return 0;
}
执行后创建新文件”1.txt”,打开后内容如下:
读写二进制文件
读写二进制文件和文本文件类似,只是在 fopen 的第二个参数有细微不同。
//往文件写入二进制数据
int main()
{
FILE *fw = fopen("2.txt","wb"); //b 表示二进制文件
assert(fw != NULL);
int arr[] = {1,2,3,4,5,6,7,8,9,10};//写入的数据
fwrite(arr,sizeof(int),10,fw); //整个整型数组直接写入文件
fclose(fw);
return 0;
}
由于写入的二进制数据,那么这个文件是不能直接查看的。
随机读,写文件
随机读写不是按数据在文件中的物理位置依次进行读写,而是可以对任何位 置上的数据进行访问。
一首歌从头开始听就是顺序读,如果你直接拖动进度条到第 1 分钟时开始听 就是随机读。
看电影时直接跳过片头也是随机读。
要实现随机读写操作,最重要的东东就是文件位置标记(也称文件位置指针), 这个标记类似光标,标记接下来要读写的开始位置。
随机读写的重点函数就是移动文件位置标识函数 fseek。
int fseek(FILE *stream,long offset,int origin);
fseek 函数:移动文件位置标识,参数如下:
stream:需要移动文件位置标识的文件;
offset:偏移的字节数,正数往后移,负数往前移;
origin:参照点,支持三个参照点。SEEK_SET 文件头,SEEK_CUR 文件位置标识当 文件头 文件位置标记 文件尾所有 前位置,SEEK_END 文件尾。
下面的调整文件位置标记的几个例子。
移到文件开头的第十个字节处: fseek (fp,10, SEEK_SET);
移到当前位置的后 50 个字节处: fseek (fp,50, SEEK_CUR);
移到文件倒数第 10 个字节处: fseek (fp,-10, SEEK_END);