
** 博主名称**迷途之人不知返 个人专栏: 《C语言》、《数据结构》、《C》、《Linux》️ Gitee仓库: 《C语言》、《数据结构》、《C》、《Linux》/ 算法专栏: 《算法精选集》C文件操作1、fopen fclose2、fprintf fputs fwrite2.1、回顾“新建文件新建在当前文件”2.2、文件模式2.3、理解文件内容 读写我们曾经在C语言的学习中见过了部分常见的关于文件操作的(库)函数。这篇文章中我们将会复习这些库函数将其中涉及到的知识与操作系统做一个简单的关联1、fopen fcloseFILE*fopen(constchar*pathname,constchar*mode);其中FILE*我们可能还记得是“文件指针”。实际上FILE*又叫“句柄”。只要我们拿着FILE*变量就可以对被打开的文件做任何操作。分析fopen的参数列表const char *pathname这个参数很明显就是要我们输入文件所在的路径如果显示输入文件的路径fopen就会打开指定路径下的文件如果不显示输入即只输入文件名fopen就会去默认的**当前路径(CWD)**找同名文件并打开。也就是说不带路径并不意味着不需要路径。const char *mode这个参数是文件打开的模式即文件是“怎样被打开的”。文件打开的模式有六种我们在下面的学习中会详细介绍这些打开模式。分析fopen的返回值成功返回FILE*变量失败返回NULL然后错误将会被报告至于fclose我们目前理解为“关闭文件”即可。只要使用fopen打开了文件我们就在最后加上fclose即可。#includestdio.hintmain(){FILE*fpfopen(log.txt,w);// ...fclose(fp);return0;}2、fprintf fputs fwrite这三个库函数都可以向文件做写入。但是它们之间有细节上的差别。fprintf我们知道printf直接向标准输出流做写入而fprintf就是指定流做写入那么fprintf就可以指定一个文件(流)然后写入内容到文件中。值得注意的是fprintf和printf一样对于输入的任意类型的变量都可以转化成字符串再输入到流中即做格式化输入。#includestdio.h#includestdlib.hintmain(){FILE*pffopen(log.txt,w);if(NULLpf){perror(fopen failed!\n);exit(1);}intcnt10;while(cnt){fprintf(pf,Hello world. cnt: %d\n,cnt);--cnt;}if(pf)fclose(pf);return0;}fputsintfputs(constchar*s,FILE*stream);fputs就是向指定流里写入字符串。#includestdio.h#includestdlib.hintmain(){FILE*pffopen(log.txt,w);if(NULLpf){perror(fopen failed!\n);exit(1);}intcnt10;constchar*messageHello text.\n;while(cnt--)fputs(message,pf);if(pf)fclose(pf);return0;}fwritesize_tfwrite(constvoid*ptr,size_tsize,size_tnmemb,FILE*stream);fwrite的作用是向指定流写入任意类型的数组。其中size数组元素的大小(字节数)。比如对于int我们可以写sizeof(int)nmemb数组元素的个数#includestdio.h#includestdlib.h#includestring.hintmain(){FILE*pffopen(log.txt,w);if(NULLpf){perror(fopen failed!\n);exit(1);}constchar*strabc\n;intcnt10;while(cnt--)fwrite(str,sizeof(str[0]),strlen(str),pf);if(pf)fclose(pf);return0;}2.1、回顾“新建文件新建在当前文件”还记得吗文件新建后为什么就在“当前路径”因为有环境变量。使用系统调用chdir对当前进程的环境变量PWD做修改我们就可以设计程序在指定的路径新建一个文件#includestdio.h#includestdlib.h#includestring.h#includeunistd.hintmain(){chdir(/home/yzc);//char pwd[64];//getcwd(pwd, sizeof(pwd));//printf(%s\n, pwd);FILE*pffopen(log.txt,w);fclose(pf);return0;}2.2、文件模式w模式/* w: Truncate file to zero length or create text file for writing. The stream is positioned at the beginning of the file. */以w模式打开文件如果文件不存在新建一个同名文件如果文件存在清空文件内容从文件的开头开始写入还记得吗想清空文件我们可以执行命令log.txt往文件log.txt中写入“空”。实际上输出重定向操作符转化成了以w模式打开文件写入内容再关闭文件的操作。(w模式打开文件会清空文件内容)a模式/* a: Open for appending (writing at end of file). The file is created if it does not exist. The stream is positioned at the end of the file. */a意为append“追加”的意思。以a模式打开文件如果文件不存在新建文件如果存在在文件的末尾位置开始写入(不做清空操作)类比上面关于输出重定向与w模式关系的讨论我们也可以得出追加输出重定向转化成了以a模式打开文件写入内容再关闭文件的操作。r模式r模式下进行的是读取。#includestdio.h#includestdlib.h#includeunistd.hintmain(){FILE*pffopen(log.txt,r);if(NULLpf){perror(fopen failed!\n);exit(1);}charinbuf[64];while(fgets(inbuf,sizeof(inbuf),pf))// 将 log.txt 的内容读取到 inbuf 中{printf(%s,inbuf);sleep(1);}fclose(pf);return0;}2.3、理解文件内容 读写文件内容实际上就相当于一个一维数组char content[]在用户的视角下文件log.txt的内容可能是这样的abcd1234而在操作系统的视角下文件log.txt的内容却是这样的abcd\n1234我们可以得出结论所谓文件内容其实就是操作系统维护了一个一维数组char content[]那么w模式下从文件的beginning开始写入就是在content的0下标开始写入a模式下从文件的ending开始写入就是在content的strlen(content)下标开始写入。这里我们可以理解为末尾开始写入的时候content数组会扩容读写维护一个int index我们如何知道读写文件到了哪一个位置答案是操作系统维护了一个int index定位读写content的位置。也就是说index存储的是content的下标值。所以我们有库函数ftell告诉我们index此时的位置#includestdio.h#includestdlib.h#includeunistd.hintmain(){FILE*pffopen(log.txt,r);if(NULLpf){perror(fopen failed!\n);exit(1);}longposftell(pf);while(1){posftell(pf);intchfgetc(pf);if(chEOF)break;elseif(\nch)printf(%ld: \\n\n,pos);elseprintf(%ld: %c\n,pos,ch);sleep(1);}fclose(pf);return0;}但是由于index只有一个所以使用 w r a 模式的时候当我们读 / 写完后index已经发生了变化再想写 / 读的话需要重新调整index。(这就比较麻烦)