一:文件指针和流
1:文件指针
1.缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”。
2.每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。
3.这些信息是保存在一个结构体变量中的。该结构体类型是由系统
声明的,取名FILE.
1.不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。 2.每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,使用者不必关心细节。 3.一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。 下面我们可以创建一个FILE* 的指针变量: FILE* pf;//文件指针变量 4.定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。 5.通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联的文件。
2:流
流:一个抽象的概念 引入流的原因: 因为计算机可以跟许许多多各种各样的外部设备进行交互,不断地输入与输出信息 所以程序员在写程序的时候就需要针对不同外部设备学习输入与输出的方式 为了简化程序员写代码的难度和过程,引入了流这样的概念 程序员只需要向流中输入数据,从流中读取数据 而无需关心流如何与外部设备之间的信息交互,比如信息如何到文件中去,如何到屏幕上面等等这些问题 这些问题是由C语言和操作系统共同完成的 而C语言程序,只要运行起来,默认就打开3个流 1.标准输入流 stdin FILE* 2.标准输出流 stdout FILE* 3.标准错误流 stderr FILE*
二:文件的打开与关闭
文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。
在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指针和文件的关系。
1.fopen与fclose函数
打开文件 FILE* fopen(const char* filename, const char* mode); 关闭文件 int fclose(FILE* stream);
fopen:
1. 如果文件成功打开,该函数将返回指向 FILE 对象的指针,该对象可用于在将来的操作中标识流。 2. 否则,将返回空指针。 3. 在大多数库实现中,errno 变量在失败时也设置为特定于系统的错误代码。
fclose:
1. 如果流成功关闭,则返回零值。 失败时,将返回 EOF。 2.fclose具有刷新缓冲区的功能 3.在VS2022的<stdio.h>头文件中,EOF是这么被定义的,即宏定义为-1 #define EOF (-1)
2.文件打开方式
文件使用方式 含义 如果指定文件不存在 “r”(只读) 为了输入数据,打开一个已经存在的文本文件 出错 “w”(只写) 为了输出数据,打开一个文本文件 建立一个新的文件 “a”(追加) 向文本文件尾添加数据 建立一个新的文件 “rb”(只读) 为了输入数据,打开一个二进制文件 出错 “wb”(只写) 为了输出数据,打开一个二进制文件 建立一个新的文件 “ab”(追加) 向一个二进制文件尾添加数据 建立一个新的文件 “r + ”(读写) 为了读和写,打开一个文本文件 出错 “w + ”(读写) 为了读和写,建立一个新的文件 建立一个新的文件 “a + ”(读写) 打开一个文件,在文件尾进行读写 建立一个新的文件 “rb + ”(读写) 为了读和写打开一个二进制文件 出错 “wb + ”(读写) 为了读和写,新建一个新的二进制文件 建立一个新的文件 “ab + ”(读写) 打开一个二进制文件,在文件尾进行读和写 建立一个新的文件
3:实例演示
int main() { FILE* pf = fopen("data.txt", "r"); //打开同级文件路径下的data.txt文件 if (pf == NULL)//对有无文件进行判断 { perror("fopen");//打印错误信息 return 1; } //关文件 fclose(pf); pf = NULL; return 0; }
三:文件的顺序读写
顺序读写:每次读写完一次之后文件指针就会后移
使用者无法指定文件指针的位置
功能 函数名 适用于 字符输入函数 fgetc 所有输入流 字符 字符输出函数 fputc 所有输出流 字符 文本行输入函数 fgets 所有输入流 字符串 文本行输出函数 fputs 所有输出流 字符串 格式化输入函数 fscanf 所有输入流 格式 格式化输出函数 fprintf 所有输出流 格式 二进制输入 fread 文件 二进制输出 fwrite 文件
一:fgetc与fputc函数
两者被称为字符输入/输出函数.
仅能适用于字符型数据,
不过可以适用于所有输入流(文件,键盘等等),或者是可以适用于所有输出流(文件,屏幕打印等等)
1:fgetc总述
fgetc int fgetc(FILE * stream); 功能总述:从流中获取一个字符 1. 返回文件指针所读取到的字符(强转为int类型) 2. 然后文件指针向后偏移至下一个要读取的数据处 3. 当文件读取结束后,该函数返回EOF
下面我们看一下实例
2:fgetc使用实例
我们提前就已经创建好了data.txt这个文件了
int main() { FILE* pf = fopen("data.txt", "r");//注意我们在这里要进行读取的操作,所以以"r"的方式打开 if (pf == NULL) { perror("fopen"); return 1; } //读文件 int ch = 0; while ((ch = fgetc(pf)) != EOF) { printf("%c\n", ch); } //关文件 fclose(pf); pf = NULL; return 0; }
这是我自己提前录入到data.txt中的信息
这是最后打印出的数据的信息
3:fputc总述
fputc int fputc(int character, FILE * stream); 功能总述:向流中写入一个数据 1. 把一个字符写入流中然后移动文件指针 2. 成功后,将返回所写字符。 如果发生写入错误,则返回 EOF并设置错误指示器(ferror)。
4:fputc使用实例
一开始,我们的data.txt中依然是存放的abcdefghi,然后我们进行写入操作
注意,写入操作会先清空原有数据,然后再进行写入!!!
int main() { FILE* pf = fopen("data.txt", "w");//写文件用"w"打开方式 if (pf == NULL) { perror("fopen"); return 1; } //写文件 int i = 0; for (i = 0; i < 26; i++) { fputc('a' + i, pf);//abcdefghijklmnopqrstuvwxyz //打印到屏幕上 //fputc('a' + i, stdout); //fputc('a' + i, stderr); } //关文件 fclose(pf); pf = NULL; return 0; }
二:fgets与fputs函数
两者被称为文本行输入/输出函数.
1.仅适用于字符串类型的数据
2.不过可以适用于所有输入流(文件,键盘等等),或者是可以适用于所有输出流(文件,屏幕打印等等)
3.注意:fputs可以一次写一行数据到流中,但是不会自动换行,如果想要换行,则需要自行添加’\n’换行符
1:fgets总述
fgets char* fgets(char* str, int num, FILE * stream); 功能总述:从流中获取一行字符串 1. 把从流中读取到的num-1个字符存入str这个字符串中 1.1.读够num-1个后不读了 1.2.读到'\n'后不读了 2. 换行符使 fgets 停止读取,但它被函数视为有效字符,并包含在复制到 str 的字符串中。 返回值 1.成功后,函数返回 str。 2.如果在尝试读取字符时遇到文件末尾,则设置 eof 指示器 (feof)。 3.如果在读取任何字符之前发生这种情况,则返回的指针为空指针(str 的内容保持不变)。
2:fgets使用实例
此时文件已经提前被改回为abcdefghi
int main() { FILE* pf = fopen("data.txt", "r"); if (NULL == pf) { perror("fopen"); return 1; } //读文件-读一行 char arr[10] = { 0 }; fgets(arr, 10, pf); printf("%s\n", arr); //关闭文件 fclose(pf); pf = NULL; return 0; }
上述data.txt文件中存放的数据是:abcdefghi
3:fputs总述
int fputs(const char* str, FILE * stream); 1.功能总述:向流当中写入一行字符串 2. 从str中读取数据写到流中 3. 该函数从指定的地址 (str) 开始复制,直到到达终止空字符 ('\0')。 此终止空字符不会复制到流中。
4:fputs使用实例
int main() { FILE* pf = fopen("data.txt", "w"); if (NULL == pf) { perror("fopen"); return 1; } //写文件,写一行 //fputs只负责写入那一行数据,不会给你换行,要是想换行,自己加'\n' fputs("hello world", pf); fputs("hello friend", pf); //关闭文件 fclose(pf); pf = NULL; return 0; }
三:fscanf与fprintf函数
两者被称为格式化输入/输出函数.
1.可以针对于格式化的数据,例如:结构体
2.可以适用于所有输入流(文件,键盘等等),或者是可以适用于所有输出流(文件,屏幕打印等等)
1:fprintf总述
fprintf int fprintf ( FILE * stream, const char * format, ... ); 1.功能总述:将格式化数据写入流 2.将按格式指向流的 C 字符串写入流。如果 format 包含格式占位符(以 % 开头的子序列),则格式后面的其他参数将被格式化并插入到生成的字符串中,替换其各自的占位符。 3.在 format 参数之后,函数至少需要与格式指定的一样多的其他参数。 例如: struct S s1 = { 100,3.14f }; fprintf(pf, "%d %f\n", s1.a, s1.s);
2:fprintf使用实例
在这里为了演示fprintf与fscanf对于格式化数据的处理,定义了一个结构体S
struct S { int a; float s; }; int main() { FILE* pf = fopen("data.txt", "w"); if (NULL == pf) { perror("fopen"); return 1; } //写文件 struct S s1 = { 100,3.14f }; fprintf(pf, "%d %f\n", s1.a, s1.s); struct S s2 = { 100,3.14f }; fprintf(pf, "%d %f", s2.a, s2.s); //关闭文件 fclose(pf); pf = NULL; return 0; }
fprintf跟fputs相似,也不会自动进行换行,必须自行加上换行符’\n’后才会换行
3:fscanf总述
fscanf int fscanf ( FILE * stream, const char * format, ... ); 1.功能总述:从流中读取格式化数据写入对应的格式型数据类型的变量中 例子: struct S s = {0}; fscanf(pf, "%d %f", &(s.a), &(s.s));
4:fscanf使用实例
int main() { FILE* pf = fopen("data.txt", "r"); if (NULL == pf) { perror("fopen"); return 1; } //读文件 struct S s = {0}; fscanf(pf, "%d %f", &(s.a), &(s.s)); printf("%d %f", s.a, s.s); //关闭文件 fclose(pf); pf = NULL; return 0; }