☰
【基础IO】-2-C语言中的文件操作
2026/10/20 11:13:33 网站建设 项目流程

**🎬 博主名称**:迷途之人不知返

🔥 个人专栏: 《C语言》、《数据结构》、《C++》、《Linux》

🗂️ Gitee仓库: 《C语言》、《数据结构》、《C++》、《Linux》

</> 算法专栏: 《算法精选集》


C文件操作

  • 1、fopen & fclose
  • 2、fprintf & fputs & fwrite
    • 2.1、回顾“新建文件,新建在当前文件”
    • 2.2、文件模式
    • 2.3、理解:文件内容 & 读写

我们曾经在C语言的学习中,见过了部分常见的关于文件操作的(库)函数。这篇文章中,

  • 我们将会复习这些库函数
  • 将其中涉及到的知识,与操作系统做一个简单的关联

1、fopen & fclose

FILE*fopen(constchar*pathname,constchar*mode);



其中,FILE*我们可能还记得是“文件指针”。实际上FILE*又叫“句柄”。

只要我们拿着FILE*变量,就可以对被打开的文件做任何操作。






分析fopen的参数列表:

const char *pathname

这个参数,很明显就是要我们输入文件所在的路径,

  • 如果显示输入文件的路径,fopen就会打开指定路径下的文件;
  • 如果不显示输入,即只输入文件名,fopen就会去默认的**当前路径(CWD)**找同名文件并打开。

也就是说:不带路径,并不意味着不需要路径。

const char *mode

这个参数是文件打开的模式,即文件是“怎样被打开的”。

文件打开的模式有六种:

我们在下面的学习中,会详细介绍这些打开模式。






分析fopen的返回值:

  • 成功,返回FILE*变量
  • 失败,返回NULL,然后错误将会被报告




至于fclose,我们目前理解为“关闭文件”即可。只要使用fopen打开了文件,我们就在最后加上fclose即可。




#include<stdio.h>intmain(){FILE*fp=fopen("log.txt","w");// ...fclose(fp);return0;}



2、fprintf & fputs & fwrite

这三个库函数都可以向文件做写入。但是它们之间有细节上的差别。

fprintf

我们知道,printf直接向标准输出流做写入;而fprintf就是指定流做写入,那么fprintf就可以指定一个文件(流),然后写入内容到文件中。

值得注意的是,fprintf和printf一样,对于输入的任意类型的变量,都可以转化成字符串再输入到流中,即做格式化输入。




#include<stdio.h>#include<stdlib.h>intmain(){FILE*pf=fopen("log.txt","w");if(NULL==pf){perror("fopen failed!\n");exit(1);}intcnt=10;while(cnt){fprintf(pf,"Hello world. cnt: %d\n",cnt);--cnt;}if(pf)fclose(pf);return0;}



fputs




intfputs(constchar*s,FILE*stream);



fputs就是向指定流里写入字符串。




#include<stdio.h>#include<stdlib.h>intmain(){FILE*pf=fopen("log.txt","w");if(NULL==pf){perror("fopen failed!\n");exit(1);}intcnt=10;constchar*message="Hello text.\n";while(cnt--)fputs(message,pf);if(pf)fclose(pf);return0;}



fwrite




size_tfwrite(constvoid*ptr,size_tsize,size_tnmemb,FILE*stream);



fwrite的作用是向指定流写入任意类型的数组。其中,

  • size:数组元素的大小(字节数)。比如对于int,我们可以写sizeof(int)
  • nmemb:数组元素的个数



#include<stdio.h>#include<stdlib.h>#include<string.h>intmain(){FILE*pf=fopen("log.txt","w");if(NULL==pf){perror("fopen failed!\n");exit(1);}constchar*str="abc\n";intcnt=10;while(cnt--)fwrite(str,sizeof(str[0]),strlen(str),pf);if(pf)fclose(pf);return0;}



2.1、回顾“新建文件,新建在当前文件”

还记得吗:文件新建后,为什么就在“当前路径”?因为有环境变量。







使用系统调用chdir,对当前进程的环境变量PWD做修改,我们就可以设计程序,在指定的路径新建一个文件:

#include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.h>intmain(){chdir("/home/yzc");//char pwd[64];//getcwd(pwd, sizeof(pwd));//printf("%s\n", pwd);FILE*pf=fopen("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模式下进行的是读取。




#include<stdio.h>#include<stdlib.h>#include<unistd.h>intmain(){FILE*pf=fopen("log.txt","r");if(NULL==pf){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此时的位置:




#include<stdio.h>#include<stdlib.h>#include<unistd.h>intmain(){FILE*pf=fopen("log.txt","r");if(NULL==pf){perror("fopen failed!\n");exit(1);}longpos=ftell(pf);while(1){pos=ftell(pf);intch=fgetc(pf);if(ch==EOF)break;elseif('\n'==ch)printf("%ld: \\n\n",pos);elseprintf("%ld: %c\n",pos,ch);sleep(1);}fclose(pf);return0;}




但是,由于index只有一个,所以使用 w+ r+ a+ 模式的时候,当我们读 / 写完后,index已经发生了变化;再想写 / 读的话,需要重新调整index。(这就比较麻烦)

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询