1.文件是什么?
在此电脑中的c盘和d盘中的文件夹就是文件,也就是磁盘上的文件就是文件。在程序设计中,我们需要谈论的是程序文件和数据文件。
1.1 程序文件
源程序文件(后缀.c)、目标文件(windows环境后缀.obj)、可执行程序(后缀.exe)
1.2 数据文件
存放数据的文件
我们在学习c语言程序的时候用到的printf、scanf输入输出数据的都是以终端为对象,即从终端的键盘输入数据,运行结果显示到显
示器上。其实也可以把信息放在磁盘上,需要的时候从磁盘上把数据读到内存中使用。
1.3 文件名
文件名包括三个部分:文件路径+文件名主干+文件后缀
例如:D:\App\DingDing
2. 为什么使用文件
我们平时写的代码在运行时数据放在内存中,当程序退出的时候,数据自然就不存在了,占用的内存空间返回给了操作系统,这样当我们使用的时候就必须运行程序重新录入数据,这样使用就很麻烦。所以有不有方法让数据保留下来,我们不需要时再删除,需要的时候直接拿出来用呢?方法是有的,把数据存放在磁盘文件和数据库等方式都是可行的。这里使用磁盘文件就是把数据放在电脑磁盘上,使得数据持久化。
3. 文件的打开和关闭
3.1 文件指针
每个被使用的文件其实都在内存中开辟了一个文件信息区,用来存放文件信息。这些信息都是保存在一个结构体变量中,该结构体类型时系统声明的,类型是FILE。
那么用一张图来解释一下这个文件信息区:
在Visual Studio 2013编译环境中合格文件结构体是这样的:
struct _iobuf { char* _ptr; int _cnt; char* _base; int _flag; int _file; int _charbuf; int _bufsiz; char* _tmpfname; }; typedef struct _iobuf FILE;
这个struct _iobuf结构体类型重新定位为FILE,每当我们打开文件,系统就会根据文件的情况自动创建一个FILE结构体类型,填充文件信息,我们不需要关心FILE结构体中是怎么用的,怎么实现的,我们只需要知道打开文件就会出现一个对应的文件信息区,这个文件信息区是存放在内存中的,就相当于这个文件结构体类型,所以使用的时候通过文件指针找到这个文件结构体,也就是文件信息区,这里就是文件指针的概念。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联的文件。
3.2 文件的打开和关闭
3.2.1 了解fopen和fclose库函数
3.2.1.1 fopen库函数
3.2.1.1.1 基本函数参数
FILE* fopen(const char* filename, const char* mode);
filename:包含要打开的文件名的C字符串(它的值应该遵循运行环境的文件名规范,可以包含路径)
mode: 包含文件访问模式的C字符串
3.2.1.1.2 注意要点
- 返回的指针可以通过调用fclose或freopen从文件中解关联。所有打开的文件在正常程序终止时自动关闭。
- 如果文件被成功打开,该函数返回一个指向file对象的指针,可用于未来操作中识别流,否则返回NULL指针。
3.2.1.2 fcolse库函数
3.2.1.2.1 基本函数参数
int fclose(FILE* stream);
stream: 指向FILE对象的指针,该对象指定要关闭的流。
3.2.1.2.2 注意要点
如果流成功关闭,则返回零值。如果失败,则返回EOF。
3.2.2 文件使用方式
3.2.3 使用
int main() { //打开文件 //打开c盘下的test文件夹中的test.txt时,在内存中映射了一块有关此文件的文件信息区, //这个文件信息区的类型是FILE结构体类型,然后把地址给到pf文件指针,就可以通过pf指针来访问这块文件信息区。 FILE* pf = fopen("c:\\test\\test.txt", "w"); if (pf == NULL) { perror("fopen():"); } //关闭文件 //关闭文件就是指通过这个文件指针关闭这个文件信息区,进而关闭此文件 fclose(pf); pf = NULL; return 0; }
4. 文件顺序读写
4.0 铺垫
4.1 使用函数
4.2 函数介绍
4.2.1 fgetc和fputc
4.2.1.1 fputc库函数
4.2.1.1.1 基本函数参数
int fputc ( int character, FILE * stream );
作用:将字符写入流
character:要写的字符的int提升。写入时,该值在内部转换为无符号字符
sream: 指向标识输出流的FILE对象的指针
4.2.1.1.2 注意要点
- 如果成功,则返回所写的字符。
- 如果发生写错误,则返回EOF并设置错误指示符
4.2.1.1.3 使用
#include <stdio.h> int main() { //打开文件 //打开c盘下的test文件夹中的test.txt时,在内存中映射了一块有关此文件的文件信息区, //这个文件信息区的类型是FILE结构体类型,然后把地址给到pf文件指针,就可以通过pf指针来访问这块文件信息区。 FILE* pf = fopen("c:\\test\\test.txt", "w"); if (pf == NULL) { perror("fopen():"); return 1; } //写入数据 int i = 0; for (i = 0; i < 26; i++) { fputc('a' + i,pf); } //关闭文件 //关闭文件就是指通过这个文件指针关闭这个文件信息区,进而关闭此文件 fclose(pf); pf = NULL; return 0; }
运行结果:
4.2.1.2 fgetc库函数
4.2.1.2.1 基本函数参数
int fgetc ( FILE * stream );
作用:从流中获取字符
stream:指向标识输入流的FILE对象的指针
4.2.1.2.2 注意要点
- 如果成功,则返回已读取的字符
- 如果调用时流位于文件末尾,则函数返回EOF并为流设置文件末尾指示符,如果发生读错误,该函数返回EOF并为流设置错误指示符。
4.2.1.2.3 使用
#include <stdio.h> int main() { //打开文件 //打开c盘下的test文件夹中的test.txt时,在内存中映射了一块有关此文件的文件信息区, //这个文件信息区的类型是FILE结构体类型,然后把地址给到pf文件指针,就可以通过pf指针来访问这块文件信息区。 FILE* pf = fopen("c:\\test\\test.txt", "r"); if (pf == NULL) { perror("fopen():"); return 1; } //读取数据 int ch = 0; while ((ch = fgetc(pf)) != EOF) { printf("%c ", ch); } //关闭文件 //关闭文件就是指通过这个文件指针关闭这个文件信息区,进而关闭此文件 fclose(pf); pf = NULL; return 0; }
4.2.2 fgets和fputs
4.2.2.1 fputs库函数
4.2.2.1.1 基本函数参数
int fputs ( const char * str, FILE * stream );
作用:将字符串写入流
str: 包含要写入流的内容的C字符串。
stream: 指向标识输入流的FILE对象的指针
4.2.2.1.2 注意要点
1.如果成功,则返回非负值
2.如果发生错误,该函数返回EOF并设置错误指示符(ferror)
4.2.2.1.3 使用
#include <stdio.h> int main() { //打开文件 //打开c盘下的test文件夹中的test.txt时,在内存中映射了一块有关此文件的文件信息区, //这个文件信息区的类型是FILE结构体类型,然后把地址给到pf文件指针,就可以通过pf指针来访问这块文件信息区。 FILE* pf = fopen("c:\\test\\test.txt", "w"); if (pf == NULL) { perror("fopen():"); return 1; } //写入数据 fputs("hello world!\n", pf); char arr[] = "abcdef"; fputs(arr, pf); //关闭文件 //关闭文件就是指通过这个文件指针关闭这个文件信息区,进而关闭此文件 fclose(pf); pf = NULL; return 0; }
运行结果:
4.2.2.2 fgets库函数
4.2.2.2.1 基本函数参数
char * fgets ( char * str, int num, FILE * stream );
作用:从流中获取字符串
str: 指针插入到一个字符数组中,读取的字符串在其中被复制
num: 要复制到str的最大字符数(包括终止的空字符)。
stream: 指向标识输入流的FILE对象的指针。
4.2.2.2.2 注意要点
- 如果成功,函数返回str。
- 如果读取字符时遇到文件结束符,则设置eof指示符。如果在读取任何字符之前发生这种情况,则返回的指针是空指针(并且str的内容保持不变)。如果发生读错误,则设置错误指示符(ferror)并返回空指针(但str所指向的内容可能已更改)