C语言对文件的操作

C语言对文件的操作前言在谭浩强的 C 语言设计的第 10 张讲了有关文件的知识 以往我们写的 C 程序的数据都是由键盘输入的现在我们要对文件进行操作 文件是操作系统的基本单位 是我们专业领域的重要的一部分 就拿我们的编译器来说 我们写了一个程序 成功的运行了 编译系统会主动的生成 3 个文件如下图它们分别是源程序文件 c 目标文件 o 可执行文件 exe 在实际的情况下 常常要把一些数据输出到磁盘上保存起来 在需要时送

前言在谭浩强的C语言设计的第10张讲了有关文件的知识,
以往我们写的C程序的数据都是由键盘输入的
现在我们要对文件进行操作。




它们分别是源程序文件.c
目标文件.o
可执行文件.exe




在实际的情况下,常常要把一些数据输出到磁盘上保存起来,在需要时送入内存之中这就需要我们用到磁盘文件。

1.文件名
一个文件要有一个唯一的文件标识以便识别和引用,分别为
1.路径(用来找到文件)
2.名称(识别是什么)
3.后缀(文件的格式或属性)








在这里插入图片描述

2.文件的分类
书上将文件分成两类,分别是
ASCII文件二进制文件
1.ASCII文件我们在刚刚接触c语言时就了解了ASCII标,每个特定的数代表一个字符,那么将字符形式的文件就是ASCII文件,也称为文本文件,每个字节存放一个字符的ASCII值。
2.二进制文件
数据在内存中是以二进制形式存储的(因为CPU只认识0和1),如果不加转换的输出到外存,就是二进制文件。也称之为映像文件
(因为从二进制转换到ASCII需要一定的时间,占的空间也更多,加之二进制文件的实用优点,我们生活中常用二进制的文件。)












3.缓冲区概念
我们都知道,在计算机的存储设备中,CPU的缓存速度是最快的,其次是显卡的显存,DDR5的显存早就已经普及,并有被淘汰之势,再次是内存,就在这几年DDR4的内存才开始广泛的使用,最慢的就是我们的硬盘(磁盘),机械硬盘的转速很慢,最快的速度也只有200多MB一秒,尽管我们现在普遍用上了固态硬盘,还是M.2协议的,但是和内存的差距依旧很大。因为两者的差距太大,就必须在数据写入磁盘时就有必要在内存中开辟一片缓冲区(所以缓冲区不是什么高大上的东西)

4.文件类型指针
回顾前面的知识,指针必须要有基类型(指向),如int p,floatp…。
那么顾名思义文件指针就是指向文件的,其实文件在C语言中是,一种结构体
也就是和结构体指针是一样的。
以下是文件结构体的定义,结构体的名称为FILE。








tpyedef struct { 
    short level; //缓冲区满或空的程度 unsigned flags; //文件状态标志 char fd; //文件描述符 unsigned char hold; //如缓冲区无内容不读取字符 short bsize; //缓冲区的大小 unsigned char*buffer; //数据缓冲区的位置 unsigned char*curp; //文件位置标记指针当前的指向 unsigned istemp; //临时文件指示器 short token; //用于有效性检查 }FILE //这是TC2.0中的定义 
#ifndef _FILE_DEFINED struct _iobuf { 
        char *_ptr; //文件输入的下一个位置     int _cnt; //当前缓冲区的相对位置     char *_base; //指基础位置(即是文件的其始位置)      int _flag; //文件标志     int _file; //文件的有效性验证     int _charbuf; //检查缓冲区状况,如果无缓冲区则不读取     int _bufsiz; //缓冲区大小     char *_tmpfname; //临时文件名 }; typedef struct _iobuf FILE; #define _FILE_DEFINED #endif //这是VC6。0里定义 

下面介绍关于文件的函数
1.打开与关闭文件函数
fopen 打开文件函数 (成功打开后指向该流的文件指针就会被返回,失败返回NULL)
fclose 关闭文件函数
引用方法








fopen(文件名,使用文件方式)//文件名是一个字符串,使用方式需要加双引号, 

为了使文件指针与文件建立联系我们要将函数返回的指针给我们的文件指针
像这样

FILE*fp; fp = fopen("test.txt","r");//以读的方式打开默认路径下一个叫test的文本文件 
文件使用方式 含义 如果指定的文件不存在
r(只读) 输入数据,打开一个已存在文本文件 出错
w(只写) 输出数据,打开一个文本文件 建立一个新文件
a(追加) 向文本文件尾添加数据 出错
rb(只读) 输入数据,打开一个2进制文件 出错
wb(只写) 输出数据,打开一个2进制文件 建立新文件
r+(读写) 读写,文本文件 出错
w+(读写) 读写,文本文件 建立新文件
a+(读写) 读写,文本文件 出错
rb+(读写) 读写,二进制文件 出错
wb+(读写) 读写,二进制文件 建立新文件
ab+(读写) 读写二进制文件 出错
#include  
     int main() { 
    FILE*p; //设置一个文件指针 char ch; //定义一个字符变量 if((p=fopen("test.txt","w"))==NULL) //打开一个叫test的文本文件,以只写的方式,当 出错时,即返回值为NULL时,输出错误信息 { 
    printf("ERROR"); exit(0); //关闭所有文件,终止正在执行的程序 } for(;ch!='\n';) //输入ch知道输入空格。 { 
    scanf("%c",&ch); fputc(ch,p); //将字符ch写入p所指向的文件 } fclose(p);//关闭文件 } 

在这里插入图片描述我们再到默认路径打开test.txt。

在这里插入图片描述可以看到我们在键盘里输出的Merry Christmas已经被写入了test之中

#include  
     int main() { 
    FILE*p; char ch; if((p=fopen("test.txt","r"))==NULL) //以只读的方式打开test。 { 
    printf("ERROR"); exit(0); } for(;ch!='\n';) { 
    ch=fgetc(p); //ch得到p所指文件中的每一个字符 putchar(ch); //将得到的字符输出到屏幕 } fclose(p); //关闭文件 } 

值得注意的是,在我们向文件写入的时候会将原有的内容清空再进行写入
请看我们再对test进行写入
这次我输入了happy
在这里插入图片描述
再到默认路径下打开text文件
在这里插入图片描述










 if((p=fopen("test.txt","a"))==NULL) //只需将w改为a即可 

5.顺序读写数据文件

1.读写字符函数
读字符 fgetc

fegrtc(文件指针) //从指针所指向的文件中读入一个字符 

写字符fputc

fputc(ch,fp) //把字符变量ch写到fp所指向的文件中去 
#include  
     int main() { 
    FILE*p1,*p2; //设置2个文件指针 char filename[30],filename1[30],ch; //设置2个字符数组用来输入文件名用 printf("请输入要复制的文件名\n"); gets(filename); //输入文件名 printf("请输入复制后的文件名:\n"); gets(filename1); //输入文件名 if((p1=fopen(filename,"rb"))==NULL) //打开被复制的文件 { 
    printf("ERROR"); exit(0); } if((p2=fopen(filename1,"wb"))==NULL) //写入要复制的文件名 { 
    printf("ERROR"); exit(0); } while(!feof(p1)) //用一个检查文件是否结束的函数来判断 { 
    ch=fgetc(p1); //读出每一个p1指向的文件中的字节,把ch写入到p2指向的文件中去,如果没有p2文件,则会建立一个以filename1字符数组命名的文件 fputc(ch,p2); } printf("复制成功"); fclose(p1); //用完之后,为了避免不必要的操作干扰读写,要关闭文件,即断掉文件指针与文件的联系 fclose(p2); } 
feof(文件指针) //当文件结束时返回非0值,当文件未结束时返回0 

再看刚才的循环语句

while(!feof(fp))//当返回值为0的时候执行循环,返回值非0的时候就结束循环 

当然对于文本文件文件可以不用二进制的方式处理
我们也可以把刚才的循环语句换成如下

while(!(ch=fgetc(fp))==EOF) //我们的EOF和NULL一样都是标准库里的宏定义EOF就是-1,NULL代表0 

WARNING二进制文件因为是以二进制形式保存的所以不能以字符的方式来存取的,所以不应用刚才的方式对二进制文件进行写入。

函数名 调用形式 功能 返回值
fgets fgets(str,n,fp) 从fp指向的文件读入一个长度为n-1的字符串,存放到字符数组str中去 成功返回地址str,失败返回NULL
fputs fputs(str,fp)) 把str所指向的字符串写入fp所指向的文件中 成功返回0,失败返回非零
#include  
     #define LEN 40 int main() { 
    FILE*fp; char filename[LEN],string[30]; //定义一个字符数组来存储文件里的信息 printf("请输入要打开的文件名"); gets(filename); if((fp=fopen(filename,"r"))==NULL) //以只读的方式打开文件打开文件 { 
    printf("ERROR"); exit(0); } fgets(string,20,fp); //将fp所指的文件中的20字符读取给字符串string fclose(fp); //关闭文件 puts(string); //以字符串形式输出string } 

在这里插入图片描述

6.用格式化的方式读写文本文件
在我们以前的输出输入之中,常用scanf和printf函数,我们的格式化读写函数和他们类似

名称 引用方式
fprintf fprintf(文件指针,格式字符串,输出列表)
fscanf fscanf(文件指针,格式字符串,输入列表)
#include  
     int main() { 
    int i=3;float j=4.567;char string[20]; FILE*fp; if((fp=fopen("test.txt","r+"))==NULL) //以读写的方式打开test { 
    printf("ERROR"); exit(0); } fscanf(fp,"%s",string); 把其中的字符串写入字符数组string中 puts(string); //输出由文件中写入的字符串 fprintf(fp,"%3d,%6.4f",i,j); //以%3d,%6.4的格式输入整形变量i和浮点型变量j fclose(fp); //关闭文件 } 

在这里插入图片描述
再去默认路径中打开test文件
在这里插入图片描述
7.用二进制方式向文件读写一组数据






名称 引用方式
fread fread(buffer,size,count,fp)
fwrite fwrite(buffer,size,count,fp)

也被称为数据块读写

函数原型size_t fread ( void *buffer, size_t size, size_t count, FILE *stream)

数据块读写多用于结构体变量的读写(因为结构体所占的字符数是不规则的)
下面举一个例子

#include  
     #define LEN 15 //结构体中字符串的长度 #define NUM 8 //要输入数据学生的个数 struct Student //定义学生结构体 { 
    char name[LEN]; int num; int age; char add[LEN]; }Stud[NUM]; //将数据先存放在结构体数组之中 int main() { 
    FILE*fp; int i; if((fp=fopen("stduent","wb"))==NULL) //建立一个叫student的文件以二进制形式进行打开进行写入操作, { 
    printf("ERROR"); exit(0); } printf("请输入学生数据\n"); for(i=0;i<NUM;i++) // { 
    scanf("%s%d%d%s",&Stud[i].name,&Stud[i].num,&Stud[i].age,&Stud[i].add);//输入学生数据信息 } for(i=0;i<NUM;i++) { 
    if(fwrite(&Stud[i],sizeof(struct Student),1,fp)!=1)//每次写一个结构体变量所占的字节,将输入的数据写入文件 { 
    printf("write error"); } } fclose(fp); //关闭文件 } 
#include  
     #define LEN 15 #define NUM 8  struct Student { 
    char name[LEN]; int num; int age; char add[LEN]; }Stud[NUM]; int main() { 
    FILE*fp; int i; if((fp=fopen("student","rb"))==NULL) //以二进制的方式读取 { 
    printf("ERROR"); exit(0); } printf("姓名 学号 年龄 地址\n"); for(i=0;i<NUM;i++) //将数据每次一个结构体变量所占字节的个数的数据赋给结构体变量 { 
    if(fread(&Stud[i],sizeof(struct Student),1,fp)!=1) { 
    printf("read error"); } } for(i=0;i<NUM;i++) //输出结构体变量的各个成员,输出数据 { 
    printf("%-10s%4d%4d%-15s",Stud[i].name,Stud[i].num,Stud[i].age,Stud[i].add); printf("\n"); } fclose(fp); //关闭文件 } 

PS(当文件不在编译器默认的路径时,要在文件名初加上文件的路径,
若一个文件为D:\data\student,我们要输入它的路径如下
D:\data\student因为只是一个反斜杠的话会被和后面的字符被认为是转义字符处理,
这也是我们的老师在我们刚学C语言时就教过的)






8.随机读写数据文件

1.文件位置标记即其定位

文件位置标记其实是一个文件中的一个指针
在我们的顺序读写当中,都是一个字符一个字符的读出有写入
没有出现跳跃的情况,
但在实际使用的过程中,我们不许要每次都要把文件全部都读一遍
只需要稍微的改动某些数据,
下面由本人这个灵魂画师来画一个图演示一下
在这里插入图片描述
文件位置标记的定位














rewind 功能是将文件内部的指针重新指向一个文件的开头

rewind(文件指针); 

现在把上面的代码改一下

#include  
     #define LEN 15 #define NUM 8  struct Student { 
    char name[LEN]; int num; int age; char add[LEN]; }Stud[NUM]; int main() { 
    FILE*fp,*fp1; int i; if((fp=fopen("student","rb"))==NULL) { 
    printf("ERROR"); exit(0); } if((fp1=fopen("CSDN","wb"))==NULL) //以写入的方式打开一个文件 { 
    printf("ERROR"); exit(0); } printf("姓名 学号 年龄 地址\n"); for(i=0;i<NUM;i++) //把文件中的数据读入结构体数组的元素 { 
    if(fread(&Stud[i],sizeof(struct Student),1,fp)!=1) { 
    printf("read error"); } } rewind(fp); //重置文件指针 for(i=0;i<NUM;i++) //写入新的文件中 { 
    if(fwrite(&Stud[i],sizeof(struct Student),1,fp1)!=1) { 
    printf("read error"); } } for(i=0;i<NUM;i++) //输出文件数据 { 
    printf("%-10s%4d%4d%15s",Stud[i].name,Stud[i].num,Stud[i].age,Stud[i].add); printf("\n"); } fclose(fp); fclose(fp1); } 

运行如前面的图一样,默认路径中出现了一个名为CSDN的文件,里面存放着学生的数据

fseek函数,文件指针位置函数
引用方法为

fseek(文件指针,位移量,起始点)
起始点 名字 用数字代表
文件开始位置 SEEK_SET 0
文件当前位置 SEEK_CUR 1
文件末尾位置 SEEK_END 2
fseek(fp,100L,0);//将文件位置标记向前移动到离文件开头100个字节处 fseek(fp,50L,1);//将文件位置标记前移到离当前位置50个字节处 fseek(fp,-10L,2);//将文件位置标记从文件末尾后退10个字节 

在上面的代码出修改一下

 for(i=0;i<NUM;i+=2) { 
    fseek(fp,i*sizeof(struct Student),0);//跳过每次移动2个结构体所占的字节 printf("%-10s%4d%4d%15s",Stud[i].name,Stud[i].num,Stud[i].age,Stud[i].add); printf("\n"); } 

感想:这是我的C语言博客的结束篇,在这2个多月的学习中,有困难也有喜悦,从一个小白,渐渐打开编程的一角,C语言交给我的思想,会帮我开起我的程序人生。
farewell C

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/222471.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月17日 下午3:43
下一篇 2026年3月17日 下午3:44


相关推荐

  • opc服务器不显示目录,opc客户端搜不到opc服务器

    opc服务器不显示目录,opc客户端搜不到opc服务器opc客户端搜不到opc服务器内容精选换一换ELB可以针对客户访问的业务为访问者提供个性化的管理策略,制定策略之前需要获取来访者的真实IP。TOA内核模块主要用来获取ELB转化过的访问者真实IP地址(仅支持IPv4),该插件安装在ELB后端服务器。本文档仅适用于四层(TCP协议)服务,当客户需要在操作系统中编译TOA内核模块时,可参考本文档进行配置。Linux内核版本为2.6.32块存储调优主要…

    2022年6月20日
    36
  • pip设置为清华源

    pip设置为清华源Pip 源设置 使用清华源 1 临时使用 1pipinstall ihttps pypi tuna tsinghua edu cn simplesome package2 永久更改 pip 源升级 pip 到最新的版本 gt 10 0 0 后进行配置 1pipinstallp U2pipconfigs index urlhttps pypi tuna tsinghua edu cn simple 如果您到 pip 默认源的网

    2026年3月18日
    1
  • 豆包大模型怎么上传文档

    豆包大模型怎么上传文档

    2026年3月12日
    3
  • 五分钟读懂TCP 协议——TCP协议简介

    五分钟读懂TCP 协议——TCP协议简介TCP 是互联网核心协议之一 本文介绍它的基础知识 一 TCP 协议的作用互联网由一整套协议构成 TCP 只是其中的一层 有着自己的分工 图片说明 TCP 是以太网协议和 IP 协议的上层协议 也是应用层协议的下层协议 最底层的以太网协议 Ethernet 规定了电子信号如何组成数据包 packet 解决了子网内部的点对点通信 图片说明 以太网协议解决了局域网的点对点通信 但是 以太网协议

    2026年3月16日
    2
  • CANalyzer添加dbc文件「建议收藏」

    CANalyzer添加dbc文件「建议收藏」打开CANalyzer新建can文件选择Analysis&Stimulation->Configuration->DatabaseManagement选择通道Channels选择其中一个右键AddDatabase选择dbc文件进行添加

    2022年6月17日
    174
  • 使用 data-* 属性来嵌入自定义数据:

    使用 data-* 属性来嵌入自定义数据:

    2021年10月17日
    48

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号