数据文件
按文件功能讲,计算机的文件分为程序文件和数据文件,数据文件操作以下简称文件操作。
程序文件:
包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)。
数据文件:
文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。
为什么要用文件操作
-
持久化存储数据:
- 文件系统提供了长期保存数据的方法,使得程序在运行结束后产生的数据依然能够保留,并且可以在程序下次运行时读取或更新这些数据。
- 这对于需要记录用户设置、保存游戏进度、创建数据库、生成日志记录等应用场景至关重要。
-
输入/输出功能:
- 文件可用于从外部源读取数据,例如文本文件、图像文件、音频文件等,作为程序的输入。
- 同样,程序处理的结果也可以写入到文件中,方便进行数据分析、报告生成或其他后续处理。
如何进行文件操作
原本我们写的程序输出一些东西的方式是把数据打印在“黑框框”上,程序结束后,打印的数据没有保存也就不见了:
以下举例为把输出的东西存在一个txt文件里
1.打开文件(引入打开方式,文件指针)
既然我们要输出东西到文件里,那我们首先需要打开一个文件,做好把数据输出到文件的准备,打开的方式如下:
FILE* pf = fopen("data.txt", "w");
这里我们会看到俩个陌生的东西,这里一一解释下:
FILE*(结构体指针):可以理解为文件指针,不过不是直接指向文件,而是指向一个存有文件信息的结构体,这个结构体是编译器自带的,下图为解释:
这个结构体就好像一个管家,有了这个管家的联系方式,就可以实现对文件的操作(告诉管家就行)。
fopen(文件打开函数):我们通过这个函数来打开函数,他会返回管家的地址(FILE*),里面的参数从左到右为1.文件名称(例子中文data.txt) 2.打开方式(例子中为“w”,可以理解为写入),确定我们打开这个文件是用来写东西的。后续我们通过这个文件管家指针来操作文件。
2.输出数据给文件(输入流概念)
3.关闭文件
文件有打开也就有关闭,在操作完文件后需要关闭文件,使用函数fclose来关闭文件:这个函数的参数直接是“文件管家”的指针就可以。
fclose(pf);
其他
文件操作还有很多的打开方式,不只是写入(w),还有以下打开方式:
文件使用方式 | 含义 | 如果指定文件不存在 |
“r”(只读) | 为了输入数据,打开一个已经存在的文本文件 | 出错 |
“w”(只写) | 为了输出数据,打开一个文本文件 | 建立一个新的文件 |
“a”(追加) | 向文本文件尾添加数据 | 建立一个新的文件 |
“rb”(只读) | 为了输入数据,打开一个二进制文件 | 出错 |
“wb”(只写) | 为了输出数据,打开一个二进制文件 | 建立一个新的文件 |
“ab”(追加) | 向一个二进制文件尾添加数据 | 建立一个新的文件 |
“r+”(读写) | 为了读和写,打开一个文本文件 | 出错 |
“w+”(读写) | 为了读和写,建议一个新的文件 | 建立一个新的文件 |
“a+”(读写) | 打开一个文件,在文件尾进行读写 | 建立一个新的文件 |
“rb+”(读写) | 为了读和写打开一个二进制文件 | 出错 |
“wb+”(读写) | 为了读和写,新建一个新的二进制文件 | 建立一个新的文件 |
“ab+”(读写) | 打开一个二进制文件,在文件尾进行读和写 | 建立一个新的文件 |
文件操作函数也很丰富,包括但不限于:
顺序读写函数:
功能 | 函数名 | 适用于 |
字符输入函数 | fgetc | 所有输入流 |
字符输出函数 | fputc | 所有输出流 |
文本行输入函数 | fgets | 所有输入流 |
文本行输出函数 | fputs | 所有输出流 |
格式化输入函数 | fscanf | 所有输入流 |
格式化输出函数 | fprintf | 所有输出流 |
二进制输入 | fread | 文件 |
二进制输出 | fwrite | 文件 |
操作文件的偏移量
可以理解为我们手敲文件的时候的光标,我们通过光标实现在哪里删除字符或增加字符:
改变偏移量(光标)函数举例:
1.int fseek ( FILE * stream, long int offset, int origin );
根据文件指针的位置和偏移量来定位文件指针:
offset:设定偏移量,例如-4代表向左便宜四个字符。
origin: 定位基准点,可以是以下三个宏之一:
1.SEEK_SET
或 0: 基于文件起始位置(即文件首字节)的偏移量。
2.SEEK_CUR
或 1: 基于当前位置的偏移量。
3.SEEK_END
或 2: 基于文件结尾位置的偏移量。
fseek
函数执行成功后,文件流的读写位置会被调整到新的位置,以便后续的读写操作可以从新位置开始。如果 fseek
失败(例如,尝试将位置设置在文件之外的位置),则返回非零值,否则返回0表示成功。
2.long int ftell ( FILE * stream );
返回文件指针相对于起始位置的偏移量
3.void rewind ( FILE * stream );
让文件指针的位置回到文件的起始位置
文件读取结束的判定
int feof(FILE *stream);
feof
函数接受一个指向 FILE
结构体的指针 stream
作为参数,这个结构体通常是由 fopen
函数打开文件后返回的文件指针所指向的。
当调用 feof(stream)
时,函数会检查与 stream
关联的内部文件结束标志(eof flag),如果该标志已经被设置,那么说明之前从该文件流中读取数据时遇到了文件的末尾,函数将返回非零值(通常为1),表示文件结束;反之,如果文件结束标志没有被设置,则返回0,表示还没有达到文件末尾。
需要注意的是,feof
并不能用来确定下一次读取操作是否会成功,因为它只反映过去读取操作的状态。在实际编程中,一般会在尝试读取文件并发生错误(比如 fgetc
或 fgets
返回 EOF)之后,再调用 feof
来确认是否是因为到达了文件尾部而导致的读取失败。同时,在连续读取文件的过程中,正确的做法通常是先尝试读取,然后检查返回值和调用 feof
来确保不会错过文件中的最后一条有效数据。