网站配置服务Wordpress,红色网站源码,宁波网站建设报价多少,信誉好的合肥网站建设相关代码gitee自取#xff1a;
C语言学习日记: 加油努力 (gitee.com)
接上期#xff1a;
学C的第三十二天【动态内存管理】_高高的胖子的博客-CSDN博客 1 . 为什么要使用文件 以前面写的通讯录为例#xff0c;当通讯录运行起来的时候#xff0c;可以给通讯录中增加、删…
相关代码gitee自取
C语言学习日记: 加油努力 (gitee.com) 接上期
学C的第三十二天【动态内存管理】_高高的胖子的博客-CSDN博客 1 . 为什么要使用文件 以前面写的通讯录为例当通讯录运行起来的时候可以给通讯录中增加、删除数据 此时数据是存放在内存中当程序退出的时候通讯录中的数据自然就不存在了 等下次运行通讯录程序的时候数据又得重新录入如果使用这样的通讯录就很难受。 既然是通讯录就应该把信息记录下来 只有我们自己选择删除数据的时候数据才不复存在。 这就涉及到了数据持久化的问题我们一般数据持久化的方法有 把数据存放在磁盘文件、存放到数据库等方式。 使用文件我们可以将数据直接存放在电脑的硬盘上做到了数据的持久化。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 2 . 什么是文件 磁盘上的文件是文件。 但在程序设计中平常讲的文件有两种从文件功能角度分类 程序文件 和 数据文件 1. 程序文件 包括 源文件后缀为 .c 目标文件windows环境后缀为 .obj 可执行程序windows环境后缀为 .exe 2. 数据文件 数据文件的内容不一定是程序而是程序运行时读写的数据 比如程序运行需要从中读取数据的文件 或者输出内容的文件。 这篇博客讨论的也是数据文件。 之前博客所处理数据的输入输出都是以终端为对象的 即从终端的键盘输入数据运行结果显示到显示器上。 其实有时候我们会把信息输出到磁盘上 当需要的时候再从磁盘上把数据读取到内存中使用 这里处理的就是磁盘上的文件。 3. 文件名 一个文件要有一个唯一的文件标识以便用户识别和引用。 文件名包含3部分 文件路径文件名主干文件后缀 例如 c:\code\test.txt 为了方便起见文件标识常被称为文件名。 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 . 文件的打开和关闭 1. 文件指针 缓冲文件系统中有个关键概念叫“文件类型指针”简称“文件指针”。 每个被使用的文件都在内存中开辟了一个相应的文件信息区 用来存放文件的相关信息如文件的名字文件状态及文件当前的位置等。 这些信息是保存在一个结构体变量中的。 该结构体类型是由系统声明的取名FILE. 例如 -- VS2013编译环境提供的 stdio.h头文件 中有以下的文件类型申明 struct _iobuf {char *_ptr;int _cnt;char *_base;int _flag;int _file;int _charbuf;int _bufsiz;char *_tmpfname;};typedef struct _iobuf FILE; 不同的C编译器的FILE类型包含的内容不完全相同但是大同小异。 每当打开一个文件的时候系统会根据文件的情况自动创建一个FILE结构体的变量 并填充其中的信息 使用者不必关心细节。 一般都是通过一个FILE的指针来维护这个FILE结构体的变量这样使用起来更加方便。 可以创建一个FILE*的指针变量: 定义pf是一个指向FILE类型数据的指针变量。 FILE* pf;//文件指针变量 可以使用pf指向某个文件的文件信息区是一个结构体变量。 通过该文件信息区中的信息就能够访问该文件。 也就是说通过文件指针变量能够找到与它关联的文件。 图解 2. 文件的打开和关闭 文件在读写之前应该先打开文件在使用结束之后应该关闭文件。 在编写程序的时候在打开文件的同时 都会返回一个FILE*的指针变量指向该文件也相当于建立了指针和文件的关系。 ANSIC 规定使用 fopen函数 来打开文件fclose函数 来关闭文件 fopen函数的参数mode 文件使用方式含义如果指定文件不存在“r”只读为了输入数据打开一个已经存在的文本文件出错(返回NULL空指针)“w”只写为了输出数据打开一个文本文件建立一个新的文件“a”追加向文本文件尾添加数据建立一个新的文件“rb”只读为了输入数据打开一个二进制文件出错(返回NULL空指针)“wb”只写为了输出数据打开一个二进制文件建立一个新的文件“ab”追加向一个二进制文件尾添加数据建立一个新的文件“r”读写为了读和写打开一个文本文件出错(返回NULL空指针)“w”读写为了读和写建立一个新的文件建立一个新的文件“a”读写打开一个文件在文件尾进行读写建立一个新的文件“rb”读写为了读和写打开一个二进制文件出错(返回NULL空指针)“wb”读写为了读和写新建一个新的二进制文件建立一个新的文件“ab”读写打开一个二进制文件在文件尾进行读和写建立一个新的文件 示例 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 4 . 文件的顺序读写 1. 顺序读写函数介绍 函数名功能适用于fgetc字符输入函数所有输入流fputc字符输出函数所有输出流fgets文本行输入函数所有输入流fputs文本行输出函数所有输出流fscanf格式化输入函数所有输入流fprintf格式化输出函数所有输出流fread二进制输入文件fwrite二进制输出文件 写输出和 读输入 “写输出” 把程序的数据写输出到文件中 “读输入” 把文件的内容读取输入到程序中 图解 ------------------------------------------------------------------------------------------------------------------------- 示例fputc 和 fgetc fputc 第一个参数 要输出的字符第二个参数 指定写入输出的目标输出流 //文件操作需要该头文件
#include stdio.h
int main()
{//创建FILE类型指针使用fopen函数进行文件操作FILE* pf fopen(data.txt, w);//第一个参数文件名可以是相对路径或绝对路径//操作失败可能会返回空指针进行检验if (pf NULL){//打印错误信息perror(fopen);return 1;}//顺序读写//写文件/*fputc(a, pf);fputc(b, pf);fputc(c, pf);*///也可以使用for循环写进文件int i 0;for (i 0; i 26; i){fputc(a i, pf);}//读文件//关闭文件fclose(pf); //这样只是文件关闭了//还需要把文件指针置为空指针pf NULL;return 0;
} fgetc 第一个参数 指定读取输入的位置输入流返回值读取到的字符 因为字符的ASCII码值为数字所以用int类型变量进行接收 //文件操作需要该头文件
#include stdio.h
int main()
{//创建FILE类型指针使用fopen函数进行文件操作FILE* pf fopen(data.txt, r);//第一个参数文件名可以是相对路径或绝对路径//操作失败可能会返回空指针进行检验if (pf NULL){//打印错误信息perror(fopen);return 1;}//顺序读写//读文件int i 0;for ( i 0; i 26; i){int ch fgetc(pf);printf(%c, ch);}printf(\n);//关闭文件fclose(pf); //这样只是文件关闭了//还需要把文件指针置为空指针pf NULL;return 0;
}------------------------------------------------------------------------------------------------------------------------- 示例fputs 和 fgets fputs 第一个参数 要输出的一行字符串如需换行要自己加\n第二个参数 指定写入输出的目标输出流 //文件操作需要该头文件
#include stdio.h
int main()
{//创建FILE类型指针使用fopen函数进行文件操作FILE* pf fopen(data.txt, w);//第一个参数文件名可以是相对路径或绝对路径//操作失败可能会返回空指针进行检验if (pf NULL){//打印错误信息perror(fopen);return 1;}//顺序读写//写文件 - 写一行fputs(hello world\n, pf);fputs(hello good good world\n, pf);// 第一个参数要输出的一行字符串换行要自己加// 第二个参数输出流填写要输出的目标//关闭文件fclose(pf); //这样只是文件关闭了//还需要把文件指针置为空指针pf NULL;return 0;
} fgets 第一个参数 用来存放从输入流读取的一行数据的字符数组 所以使用该函数时最好先准备一个字符串 第二个参数 从输入流一行中读取的字符个数遇到换行符 \n 会提前结束读取 需注意实际读取字符个数为 num-1 个能够读完的话最后一个字符会是换行符 \n不能读完则最后一个字符是结束符\0 所以使用该函数进行输入时可以不用自己加换行符 第三个参数 指定读取输入的位置输入流 //文件操作需要该头文件
#include stdio.h
int main()
{//创建FILE类型指针使用fopen函数进行文件操作FILE* pf fopen(data.txt, r);//第一个参数文件名可以是相对路径或绝对路径//操作失败可能会返回空指针进行检验if (pf NULL){//打印错误信息perror(fopen);return 1;}//顺序读写//读文件 - 读一行//读一行文件要先创建一个字符数组//来存储待会从文件读到的数据char arr[10] { 0 }; //使用fgets函数读一行fgets(arr, 10, pf);//打印读取到的数据printf(%s, arr); //直接打印用于存储的字符串即可//关闭文件fclose(pf); //这样只是文件关闭了//还需要把文件指针置为空指针pf NULL;return 0;
}------------------------------------------------------------------------------------------------------------------------- 示例fprintf 和 fscanf 上面的示例中的四个函数是对字符类型进行文本操作 这两个函数则可以对“带有格式”的数据结构体进行文本操作 fprintf 第一个参数跟printf函数相比就多了这第一个参数 指定写入输出的目标输出流第二个参数分别写出“带格式数据”的格式类似printf函数的第一个参数%d、%s……之后的参数之后的参数取决于自己需要加入多少个参数每个参数都需要在第二个参数中注明格式参数之间要用逗号隔开 #include stdio.h
struct S
{int a; //整型数据float s; //浮点型数据
};int main()
{//创建FILE类型指针使用fopen函数进行文件操作FILE* pf fopen(data.txt, w);//第一个参数文件名可以是相对路径或绝对路径//操作失败可能会返回空指针进行检验if (pf NULL){//打印错误信息perror(fopen);return 1;}//顺序读写//写文件 - fprintf函数struct S s { 100, 3.14f }; //创建结构体变量//使用fprintf函数输出带格式的数据fprintf(pf, %d %f, s.a, s.s);//关闭文件dfclose(pf); //这样只是文件关闭了//还需要把文件指针置为空指针pf NULL;return 0;
} fscanf 第一个参数跟scanf函数相比就多了这第一个参数 指定读取输入的位置输入流第二个参数分别写出“带格式数据”的格式类似scanf函数的第一个参数%d、%s……之后的参数之后的参数取决于自己需要加入多少个参数每个参数都需要在第二个参数中注明格式参数之间要用逗号隔开类似scanf函数需要加上取地址符 #include stdio.h
struct S
{int a; //整型数据float s; //浮点型数据
};int main()
{//创建FILE类型指针使用fopen函数进行文件操作FILE* pf fopen(data.txt, r);//第一个参数文件名可以是相对路径或绝对路径//操作失败可能会返回空指针进行检验if (pf NULL){//打印错误信息perror(fopen);return 1;}//顺序读写//读文件struct S s { 0 };fscanf(pf, %d %f, (s.a), (s.s));//读取后放在结构体变量s中//打印查看读取效果printf(%d %f, s.a, s.s);//关闭文件dfclose(pf); //这样只是文件关闭了//还需要把文件指针置为空指针pf NULL;return 0;
} ------------------------------------------------------------------------------------------------------------------------- 示例fwrite 和 fread fwrite 第一个参数 将要写入文件中的数据的起始地址如数组名第二个参数 写到文件中的每个数据大小如数组每个元素大小第三个参数 将要写入文件的数据个数如数组元素个数第四个参数 指定写入输出的目标输出流 #include stdio.h
//fwrite:
struct S
{int a;float s;char str[10];
};int main()
{//创建一个结构体变量struct S s { 99, 6.18f, hello };//创建FILE类型指针使用fopen函数进行文件操作FILE* pf fopen(data.txt, wb); //注二级制写文件是“wb”//第一个参数文件名可以是相对路径或绝对路径//操作失败可能会返回空指针进行检验if (pf NULL){//打印错误信息perror(fopen);return 1;}//以二级制形式写文件fwrite(s, sizeof(struct S), 1, pf);//关闭文件dfclose(pf); //这样只是文件关闭了//还需要把文件指针置为空指针pf NULL;return 0;
} fread 第一个参数给出一个地址指针 以二进制形式读取文件后把读取到的数据从该地址开始依次往后存放第二个参数 读取输入的每个数据大小如数组每个元素大小第三个参数 读取输入的数据个数如数组元素个数第四个参数 指定读取输入的位置输入流返回值会返回读取到的数据个数 可以根据返回值情况判断是否继续读取数据 #include stdio.h
//fwrite:
struct S
{int a;float s;char str[10];
};int main()
{//创建FILE类型指针使用fopen函数进行文件操作FILE* pf fopen(data.txt, rb); //注二级制读文件是“rb”//第一个参数文件名可以是相对路径或绝对路径//操作失败可能会返回空指针进行检验if (pf NULL){//打印错误信息perror(fopen);return 1;}//创建一个结构体变量//读取完二进制数据后存入改结构体变量中struct S s { 0 };//以二级制形式读取文件fread(s, sizeof(struct S), 1, pf);//读取后打印查看读取情况printf(%d %f %s\n, s.a, s.s, s.str);//关闭文件dfclose(pf); //这样只是文件关闭了//还需要把文件指针置为空指针pf NULL;return 0;
} 2. 程序运行时的三个流 在C语言程序中只要程序运行起来就默认会打开三个流 标准输入流stdin -- 可以使用 scanf、getchar 等函数 标准输出流stdout -- 可以使用 printf、putchar 等函数 标准错误流stderr 这三个流的类型都是 FILE* 指针 勿混淆stdio.h stdio.h 是一个头文件指标准输入输出 指的是从键盘上输入和把数据打印到屏幕上的这些函数的总和 补充三组易混淆的函数 scanf 和 printf scanf -- 从标准输入流读取格式化的数据printf -- 向标准输出流写入格式化的数据 fscanf 和 fprintf 上面有示例 fscanf -- 适用于所有输入流的格式化输入函数fprintf -- 适用于所有输出流的格式化输出函数 sscanf 和 sprintf sscanf -- 从字符串中读取格式化的数据“把字符串转化为结构体变量数据”sprintf -- 将格式化的数据转换为字符串“把结构体变量数据转换为字符串” ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 5 . 文件的随机读写 随机读写 随意指定文件的任意位置进行读写操作 当你使用文件指针打开对应文件的时候文件指针是指向文件起始位置的 所以要实现随机读写 就要让文件指针指向你想要的位置 1. fseek函数 跟函数可以根据文件指针的位置和偏移量来定位文件指针。 函数书写格式 int fseek ( FILE * stream, long int offset, int origin ); 对应参数和返回值描述 FILE * stream -- 参数一接收要操作文件的文件指针 long int offset -- 参数二偏移量正数向右偏移负数向左偏移 int origin -- 参数三文件操作的起始位置从哪开始偏移有三个可选择的参数SEEK SET -- 从 文件的起始位置 开始偏移SEEK CUR -- 从 当前文件指针的位置 开始偏移SEEK END -- 从 文件的末尾位置 开始偏移 示例 #include stdio.h
int main()
{FILE* pf fopen(data.txt, r);if (pf NULL){perror(fopen);return 1;}//读文件int ch fgetc(pf);printf(%c\n, ch);//ach fgetc(pf);printf(%c\n, ch);//bch fgetc(pf);printf(%c\n, ch);//c//使用参数三的 SEEK CUR 进行演示fseek(pf, -3, SEEK_CUR);ch fgetc(pf);printf(%c\n, ch);fclose(pf);pf NULL;return 0;
} 2. ftell函数 该函数会返回文件指针相对于起始位置的偏移量 函数书写格式 long int ftell ( FILE * stream ); 对应参数和返回值描述 FILE * stream -- 参数一接收要操作文件的文件指针 long int -- 返回值返回文件指针相对于起始位置的偏移量 示例 #include stdio.h
int main()
{FILE* pf fopen(data.txt, r);if (pf NULL){perror(fopen);return 1;}//读文件int ch fgetc(pf);printf(%c\n, ch);//ach fgetc(pf);printf(%c\n, ch);//bch fgetc(pf);printf(%c\n, ch);//c//使用ftell函数当前偏移量int pos ftell(pf);printf(%d\n, pos);fclose(pf);pf NULL;return 0;
} 3. rewind函数 让文件指针的位置回到文件的起始位置 函数书写格式 void rewind ( FILE * stream ); 对应参数和返回值描述 FILE * stream -- 参数一接收要操作文件的文件指针 示例
#include stdio.h
int main()
{FILE* pf fopen(data.txt, r);if (pf NULL){perror(fopen);return 1;}//读文件int ch fgetc(pf);printf(%c\n, ch);//ach fgetc(pf);printf(%c\n, ch);//bch fgetc(pf);printf(%c\n, ch);//c//使用rewind函数让文件指针回到初始位置rewind(pf);ch fgetc(pf);printf(%c\n, ch);fclose(pf);pf NULL;return 0;
} ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 6 . 文本文件 和 二进制文件 根据数据的组织形式数据文件被称为文本文件或者二进制文件。 数据在内存中以二进制的形式存储如果不加转换的输出到外存文件、硬盘 就是二进制文件。直接打开进行查看是乱码 如果要求在外存上以ASCII码的形式存储则需要在存储前转换。 以ASCII字符的形式存储的文件就是文本文件。 一个数据在内存中是怎么存储的呢 字符一律以ASCII形式存储 数值型数据既可以用ASCII形式存储也可以使用二进制形式存储。 如有整数10000 如果以ASCII码的形式输出到磁盘则磁盘中占用5个字节每个字符一个字节 而二进制形式输出则在磁盘上只占4个字节整型。 VS2013测试 图解 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 7 . 文件读取结束的判定 被错误使用的feof函数 牢记在文件读取过程中不能用feof函数的返回值直接来判断文件的是否结束。 feof函数 的作用是 当文件读取结束的时候判断 遇到文件尾 是不是读取结束的原因 读取结束还可能是因为读到中途遇到错误等等 1. 文本文件读取是否结束 可以使用 feof函数 后 判断返回值是否为 EOF fgetc 或者 NULL fgets 例如 使用 fgetc函数 后 -- 使用 feof函数 判断返回值是否为 EOF是则证明文件读取结束使用 fgets函数 后 -- 使用 feof函数 判断返回值是否为 NULL是则证明文件读取结束 2. 二进制文件的读取结束判断 可以使用 fread函数 后 判断返回值是否小于实际要读的个数。 例如 fread函数 会返回 实际读取个数 所以可以通过判断 fread函数 返回值实际读取个数是否小于实际要读的个数是则说明二进制文件读取结束 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 8 . 文件缓冲区 ANSIC 标准采用“缓冲文件系统”处理的数据文件的 所谓缓冲文件系统 是指系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区”。 从内存向磁盘输出数据会先送到内存中的缓冲区 装满缓冲区后才一起送到磁盘上。 如果从磁盘向计算机读入数据 则从磁盘文件中读取数据输入到内存缓冲区充满缓冲区 然后再从缓冲区逐个地将数据送到程序数据区程序变量等。 缓冲区的大小根据C编译系统决定的。 因为有缓冲区的存在C语言在操作文件的时候 需要做刷新缓冲区或者在文件操作结束的时候关闭文件。 如果不做可能导致读写文件的问题。 图解