【c语言进阶】文件操作(下) ╰半夏微凉° 2024-04-26 11:06 81阅读 0赞 ![在这里插入图片描述][6ac7346dc5944908b5dd227e55fab217.gif_pic_center] > ?write in front? > ?所属专栏: [c语言学习][c] > ?️博客主页:[睿睿的博客主页][Link 1] > ?️代码仓库:?[VS2022\_C语言仓库][VS2022_C] > ?您的点赞、关注、收藏、评论,是对我最大的激励和支持!!! > **关注我,关注我,关注我**,你们将会看到更多的优质内容!! ![在这里插入图片描述][85d8f838a7524c8bb8bed80b7ac059c1.gif_pic_center] #### 文章目录 #### * 前言 * 一、文件的随机读写 * * 1、fseek函数: * 2、ftell函数: * 3、rewind函数: * 4、综合使用: * 二、文本文件与二进制文件: * 三、文件结束的判定: * * 1.错误使用 feof 函数: * 2.一些判断文件结束的总结: * * 2.1. 文本文件读取是否结束: * 2.2. 二进制文件的读取结束判断, * 3.判断原因的两个函数: * 四、缓冲区的简单介绍 * 总结: ## 前言 ## 在上一篇文章中上一篇文章[文件操作知识大全(上)][Link 2],我们学习了文件操作的相关知识,比如顺序读写,文件的打开与关闭,文件指针等等。今天我们再来补充一些常用的知识点! ## 一、文件的随机读写 ## ### 1、fseek函数: ### > 根据文件指针的位置和偏移量来定位文件指针 **函数格式:** int fseek(FILE* stream, long int offset, int origin); **注意事项:** * 其中“ **offset** ”为相对于**指针位置的指针偏移量**。 * 其中“ **origin** ”为指针位置,其参数有三种: “ **SEEK\_CUR** ”表示文件指针**当前位置**; “ **SEEK\_END** ”表示文件**末尾的位置**; “ **SEEK\_SET** ”表示文件**开始位置**。 int main() { FILE* pf = fopen("test.txt", "w"); fputs("abcd", pf); fclose(pf); pf = fopen("test.txt", "r"); if (pf == NULL) { perror("fopen"); } else { int ch = fgetc(pf); printf("%c\n", ch);//a ch = fgetc(pf); printf("%c\n", ch);//b ch = fgetc(pf); printf("%c\n", ch);//c //如果继续往下读,必然是d //但是我们调整一下,去读取:b //fseek(pf, -2, SEEK_CUR); fseek(pf, 1, SEEK_SET); ch = fgetc(pf); printf("%c\n", ch);//b } return 0; } **运行结果:** ![在这里插入图片描述][57714ee5da46455e925fd4a942009bec.png] ### 2、ftell函数: ### > 返回文件指针相对于起始位置的偏移量 **函数格式:** long int ftell(FILE* stream); ### 3、rewind函数: ### > 让文件指针的位置回到文件的起始位置(其实相当于fseek(stream,0,SIZE\_SET)) 函数格式: void rewind(FILE* strname); ### 4、综合使用: ### int main() { FILE* pf = fopen("test.txt", "w"); fputs("abcd", pf); fclose(pf); pf = fopen("test.txt", "r"); if (pf == NULL) { perror("fopen"); } else { int ch = fgetc(pf); printf("%c\n", ch);//a ch = fgetc(pf); printf("%c\n", ch);//b ch = fgetc(pf); printf("%c\n", ch);//c //如果继续往下读,必然是d //但是我们调整一下,去读取:b //fseek(pf, -2, SEEK_CUR); fseek(pf, 1, SEEK_SET); ch = fgetc(pf); printf("偏移一个字符后是%c\n", ch);//b printf("总共便宜了%d\n个位置", ftell(pf)); rewind(pf); ch = fgetc(pf); printf("回到起始位置后是%c\n", ch);//a } return 0; } **运行结果:** ![在这里插入图片描述][e66f493d9af047ac85893aa8ff05f07f.png] ## 二、文本文件与二进制文件: ## * 数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。 * 如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件。 **所以,一个数据在内存中是怎么存储的呢?** 字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储。 如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而二进制形式输出,则在磁盘上只占4个字节。 ![在这里插入图片描述][a780d3ee6e294fcfb6639e1449b23bf0.png] 我们举个栗子: int main() { int a = 10000; FILE* p = fopen("test.txt", "wb"); //“wb”表示以只写模式打开二进制文件 if (p == NULL) { perror("FileOpen"); return 0; } fwrite(&a, 4, 1, p); //将变量a中的数据,每四个字节存储一次,写入文件指针p所指向的文件 fclose(p); p = NULL; return 0; } **通过文本文件发现看不懂:** ![在这里插入图片描述][45dd2bec833e432e97fb2bffb871cf86.png] 其实原因大家都知道,我们是以2进制的形式传进去的,文本文件就以这个2进制打印了字符。所以我们现在来用二进制形式看看该文件(16进制)! ![在这里插入图片描述][afe0aff77c3546d5a09c3cc670a989db.png] ![在这里插入图片描述][552c632eea444831b1d6fbec793b2c18.png] > 每四个字节进行划分: > 0000 0000 0000 0000 0010 0111 0001 0000 > 于是得到: > 00 00 27 10 又因为我们的vs是小端存储,于是在进行压栈时会将数据进行倒置存储,于是就有了该结果。 ## 三、文件结束的判定: ## ### 1.错误使用 feof 函数: ### 在一段时间的交流中,我发现有很多小伙伴们都**错误的使用**了 **feof 函数**,将其用于判断文件是否读取结束 ,而这种使用方式是**错误的**。 **我们应该记住:** * 在文件的读取过程中,**不能通过 feof 函数的返回值来判定文件是否读取结束**。 * 该函数的作用为:在**已经确定文件读取结束的情况下**,**用于判定文件读取结束的原因** ### 2.一些判断文件结束的总结: ### #### 2.1. 文本文件读取是否结束: #### 要判断返回值是否为 **EOF ( fgetc )**,或者 **NULL ( fgets )** 例如: **fgetc 判断**是否为 **EOF** . **fgets 判断**返回值是否为 **NULL** . int main() { int c; //注意:int,非char,要求处理EOF FILE* fp = fopen("test.txt", "r"); if (!fp) { perror("File opening failed"); return 1; } // fgetc 当读取失败的时候或者遇到文件结束的时候,都会返回EOF while ((c = fgetc(fp)) != EOF) // 标准C I/O读取文件循环 { putchar(c); } //判断是什么原因结束的 if (ferror(fp)) { puts("I/O error when reading"); } else if (feof(fp)) { puts("End of file reached successfully"); } fclose(fp); fp = NULL; return 0; } #### 2.2. 二进制文件的读取结束判断, #### 判断返回值是否小于实际要读的个数。 例如: **fread判断**返回值是否**小于实际要读的个数**。 #include<stdio.h> enum { SIZE = 5 }; int main(void) { double a[SIZE] = { 1.,2.,3.,4.,5. }; FILE* fp = fopen("test.bin", "wb"); //必须用二进制模式 fwrite(a, sizeof * a, SIZE, fp); //写 double 的数组 fclose(fp); double b[SIZE]; fp = fopen("test.bin", "rb"); size_t ret_code = fread(b, sizeof * b, SIZE, fp); //读 double 的数组 //判断是否读取成功 if (ret_code == SIZE) { puts("Array read successfully, contents: "); for (int n = 0; n < SIZE; ++n) printf("%f ", b[n]); putchar('\n'); } //寻找读取失败的原因: else { // error handling if (feof(fp)) { printf("Error reading test.bin: unexpected end of file\n"); } else if (ferror(fp)) { perror("Error reading test.bin"); } } fclose(fp); fp = NULL; return 0; } ### 3.判断原因的两个函数: ### ![在这里插入图片描述][830e427b35a346618cac4c848e57a9e0.png] ## 四、缓冲区的简单介绍 ## 文件缓冲区是用以**暂时存放**读写期间的**文件数据**而在内存区**预留的一定空间**。 ANSIC 标准采用“**缓冲文件系统**”处理的数据文件的,所谓缓冲文件系统是指**系统自动地在内存中为程序中每一个正在使用的文件开辟一块“文件缓冲区**”.从内存向磁盘输出数据会**先送到内存中的缓冲区,装满缓冲区**后才一起送到磁盘上。如果从磁盘向计算机读入数据,则从**磁盘文件中读取数据输入到内存缓冲区(充满缓冲区)**,然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。**缓冲区的大小根据C编译系统决定的。** ![在这里插入图片描述][5590d6f671ca4a8ba2f7bdc5fec5788a.png] 要使缓冲区的内容进入内存或者计算机硬盘有两种方法,第一种是缓冲区充满自动填入,第二个是主动刷新缓冲区。 > ![在这里插入图片描述][0828773f0a9c4bec947ce8db480487a2.png] 举个例子: #include <stdio.h> #include <Windows.h> //VS2022 WIN10环境测试 int main() { FILE* pf = fopen("test.txt", "w"); fputs("abcdef", pf); //先将代码放在输出缓冲区 printf("睡眠10秒\n"); //已经写数据了,但是打开test.txt文件,发现文件没有内容 Sleep(10000); printf("刷新缓冲区\n"); fflush(pf); //刷新缓冲区时,才将输出缓冲区的数据写到文件(磁盘) //注:fflush 在高版本的VS上不能使用了 printf("再睡眠10秒\n"); //此时,再次打开test.txt文件,文件有内容了 Sleep(10000); fclose(pf); //注:fclose在关闭文件的时候,也会刷新缓冲区 pf = NULL; return 0; } 所以在这里,各位小伙伴们一定要注意了,因为缓冲区的存在,数据只有在填满缓冲区后才会进行真正的写入或读取,所以在 C 语言程序代码的编写过程中,**我们一定要在文件操作结束时关闭文件**,否则就可能导致文件的读写操作出现问题。 ## 总结: ## 经过今天内容的补充,我们关于文件操作与管理的知识就全部学完了,不知道小伙伴们是否掌握了呢? 更新不易,辛苦各位小伙伴们动动小手,?三连走一走?? ~ ~ ~ 你们真的对我很重要!最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正! > **专栏订阅:** > [每日一题][Link 3] > [c语言学习][c] > [算法][Link 4] > [智力题][Link 5] > 更新不易,辛苦各位小伙伴们动动小手,?三连走一走?? ~ ~ ~ 你们真的对我很重要!最后,本文仍有许多不足之处,欢迎各位认真读完文章的小伙伴们随时私信交流、批评指正! ![在这里插入图片描述][55270e2552774a17a711aa978da84193.gif_pic_center] [6ac7346dc5944908b5dd227e55fab217.gif_pic_center]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/26/b169ee1464ec4447a5f380cf636b14fb.gif [c]: https://blog.csdn.net/qq_74310471/category_12157207.html?spm=1001.2014.3001.5482 [Link 1]: https://blog.csdn.net/qq_74310471?spm=1000.2115.3001.5343 [VS2022_C]: https://gitee.com/zhangxuruihhhh/c-language-learning [85d8f838a7524c8bb8bed80b7ac059c1.gif_pic_center]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/26/386c1a36c5d54684be513ce8eff27fb9.gif [Link 2]: https://blog.csdn.net/qq_74310471/article/details/128776548?spm=1001.2014.3001.5501 [57714ee5da46455e925fd4a942009bec.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/26/5fabc4b5351245e18525d70873e17fe2.png [e66f493d9af047ac85893aa8ff05f07f.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/26/40f66061402d430da23a51000bea3dda.png [a780d3ee6e294fcfb6639e1449b23bf0.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/26/0a36121c774942cda28c3a99f89b459c.png [45dd2bec833e432e97fb2bffb871cf86.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/26/4314be5540074ed8bfac1e0e7a56b095.png [afe0aff77c3546d5a09c3cc670a989db.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/26/9e73268f782d40deb093947cd5e25eaf.png [552c632eea444831b1d6fbec793b2c18.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/26/6531eb6f8f6546e5bd30db716355c34f.png [830e427b35a346618cac4c848e57a9e0.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/26/0455cf4a4aca470080325abc1e30e0db.png [5590d6f671ca4a8ba2f7bdc5fec5788a.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/26/124bcdc5c52b465a997380d02cc866f3.png [0828773f0a9c4bec947ce8db480487a2.png]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/26/dfb7d892c889470eb8359fad04f3d91f.png [Link 3]: https://blog.csdn.net/qq_74310471/category_12166401.html?spm=1001.2014.3001.5482 [Link 4]: https://blog.csdn.net/qq_74310471/category_12144452.html?spm=1001.2014.3001.5482 [Link 5]: https://blog.csdn.net/qq_74310471/category_12166402.html [55270e2552774a17a711aa978da84193.gif_pic_center]: https://image.dandelioncloud.cn/pgy_files/images/2024/04/26/bb77674cf2ff44abb730f852696c0a72.gif
相关 【C语言进阶】指针进阶(三) 指针进阶(三) 9.指针和数组笔试题解析 10.指针笔试题 9.指针和数组笔试题解析 数组名的理解 数组名是数组首元素的地址 但 朴灿烈づ我的快乐病毒、/ 2024年03月27日 18:31/ 0 赞/ 147 阅读
相关 C语言指针进阶 C语言指针进阶 一.字符指针 二.指针数组 三.数组指针 1.数组名和&数组名 2.数组指针的应用 四.数组及指针传参 忘是亡心i/ 2024年03月17日 15:58/ 0 赞/ 93 阅读
相关 C进阶:文件操作 C语言文件操作 什么是文件 > 磁盘上的数据是文件。 > > 但是在程序设计中,我们一般谈的文件有两种:程序文件(例如.c,.h这一类编译,链接过程中的文件),数 分手后的思念是犯贱/ 2023年10月13日 21:53/ 0 赞/ 65 阅读
相关 C#(Sharp)进阶篇:文件操作 文章目录 8.1 文件系统概述 8.2 驱动器、目录和文件 8.2.1 与IO操作相关的枚举 8.2.2 驱动器 8. 喜欢ヅ旅行/ 2023年01月18日 09:27/ 0 赞/ 30 阅读
相关 C语言进阶——指针进阶 C语言指针进阶 C语言初阶——指针 一、字符指针 二、数组指针 2.1 指针数组 2.2 数组指针 2.3 &数 我不是女神ヾ/ 2023年01月06日 11:57/ 0 赞/ 243 阅读
还没有评论,来说两句吧...