【C语言入门级教学】⽂件的随机读写和文件缓冲区

点击这里查看文件相关知识的第一篇(这是第三篇)

点击这里查看文件相关知识第二篇

5.11 对⽐几组函数

5.11.1 sprintf

int sprintf(char* str,const char* format,...);
//对比
int printf(const char* format,...);
//将格式化数据打印到屏幕(标准输出)上

功能

将格式化数据写入字符数组(字符串)。它类似于printf,但输出目标不是控制台或文件,而是用户指定的内存缓冲区。常用于动态生成字符串、拼接数据或转换数据格式。简而言之就是将格式化的数据转换成一个字符串

参数

str:指向字符数组的指针,用于存储生成的字符串(需确保足够大以防溢出)

format:格式化字符串,定义输出格式(如%d、%f、%s等)

…:可变参数列表,提供与格式字符串中说明符对应的数据

返回值

成功时返回写入buffer的字符数(不包括结尾的空字符\0)

失败时返回负值

代码演示

#include <stdio.h>
struct S
{
    char name[20];
    int age;
    float score;
};
int main()
{
    struct S s={"zhangsan",20,95.5f};
    char buffer[100]={0};
    sprintf(buffer,"%s %d %f",s.name,s.age,s.score);
    printf("%s\n",buffer);
    return 0;
}

5.11.2 sscanf

int sscanf(const char* str,const char* format,...);
int scanf(const char* format,...);
//从键盘上读取格式化的数据,放到变量中

功能

从字符串中读取格式化数据。它与scanf类似,但输入源是内存中的字符串而非控制台或文件。常用于解析字符串中的结构化数据(如提取文字,分割文本等)

参数

str:要解析的源字符串(输入数据来源)

format:格式化字符串,定义如何解析数据(如%d、%f、%s等)

…:可变参数列表,提供存储数据的变量地址(需与格式串中的说明符匹配)

返回值

成功时:返回成功解析并赋值的参数数量(非负值)

失败或未匹配任何数据:若输入结束或解析失败,返回EOF

代码演示

#include <stdio.h>
struct S
{
    char name[20];
    int age;
    float score;
};
int main()
{
    struct S s={"zhangsan",20,95.5f};
    char buf[100]={0};
    sprintf(buf,"%s %d %f",s.name,s.age,s.score);
    printf("%s\n",buffer);
    //还原到结构体变量中
    struct S t={0};
    sscanf(buf,"%s %d %f",t.name,&(t.age),&(t.score));//格式要对应
    printf("%s %f %d",t.name,t.score,t.age);//还原到结构体变量中,要按照格式打印
    return 0;
}

5.12总结

在这里插入图片描述

6.⽂件的随机读写

6.1 fseek

int fseek ( FILE * stream, long int offset, int origin );

功能

根据⽂件指针的位置和偏移量来定位⽂件指针(⽂件内容的光标)。

参数

FILE * stream:指向已打开文件的指针,类型为FILE*

long int offset:表示移动的字节数,类型为long

int origin:起始位置,指定偏移量的基准位置,

​ 常见选项包括:

SEEK_SET:从文件开头开始计算偏移量。

SEEK_CUR:从当前位置开始计算偏移量。

SEEK_END:从文件末尾开始计算偏移量。

返回值

成功时:返回0,表示文件指针位置已成功调整。

失败时:返回非零值(如-1),表示操作失败,可能由于文件未打开或参数无效导致。

代码演示

#include <stdio.h>  
int main () 
{ 
    FILE * pf= fopen ( "data.txt" , "r" );
    if(pf==NULL)
    {
        perror("fopen");
        return 1;
    }
    //读文件
    int ch=fgetc(pf);//a
    printf("%c\n",ch);
    
    fseek(pf,6,SEEK_SET);
    //fseek(pf,5,SEEK_CUR);
    //fseek(pf,-3,SEEK_END);
    
    ch=fgetc(pf);//g
    printf("%c\n",ch);
    
    fclose(pf);
    pf=NULL;
    return 0; 
} 

data.txt
在这里插入图片描述

写文件类似

#include <stdio.h>  
int main () 
{     
    FILE * pf= fopen ( "data.txt" , "r" );    
    if(pf==NULL)    
    {        
        perror("fopen");        
        return 1;    
    }    
    
    fputs("abcdefghi",pf);
    //写文件    
    fseek(pf,6,SEEK_SET);    
    //fseek(pf,5,SEEK_CUR);    
    //fseek(pf,-3,SEEK_END);        
    fputc('x',pf);
           
    fclose(pf);    
    pf=NULL;    
    return 0; 
} 

在这里插入图片描述

6.2 ftell

long int ftell ( FILE * stream );

功能

用于获取文件指针的当前位置,通常用于二进制文件或文本文件的操作中。该函数返回一个长整型值,表示文件指针相对于文件开头的偏移量。

参数

FILE * stream:指向文件对象的指针,表示需要查询位置的文件流。

返回值

成功时返回当前文件指针的位置(以字节为单位)。

失败时返回-1L,并设置errno以指示错误类型。

代码演示

#include <stdio.h>  
int main () 
{         
    FILE * pf= fopen ( "data.txt" , "r" );        
    if(pf==NULL)        
    {                
        perror("fopen");                
        return 1;        
    }            
    
    fputs("abcdefghi",pf);    
    //写文件        
    fseek(pf,-3,SEEK_END);            
    fputc('x',pf);
    
    int ret=ftell(pf);
    printf("%d\n",ret);
    
    fclose(pf);        
    pf=NULL;        
    return 0; 
} 

在这里插入图片描述

//巧妙借助这个函数算出文件内容长度
fseek(pf,0,SEEK_END);            
    
int ret=ftell(pf);
printf("%d\n",ret);

6.3 rewind

void rewind ( FILE * stream ); 

功能

用于将文件指针重新定位到文件的开头,同时清除文件结束标志(EOF)和错误标志。它通常用于需要重新读取文件内容的场景。

参数

FILE *stream:指向文件对象的指针,表示需要重置位置的文件流。

返回值

rewind 函数没有返回值(返回类型为 void)。如果操作失败,通常是因为传入的文件指针无效或文件未正确打开,但函数本身不会显式返回错误信息。

代码演示

#include <stdio.h>  
int main () 
{         
    FILE * pf= fopen ( "data.txt" , "r" );        
    if(pf==NULL)        
    {                
        perror("fopen");                
        return 1;        
    }            
    
    fputs("abcdefghi",pf);    
    //写文件        
    fseek(pf,-3,SEEK_END);            
    fputc('x',pf);
    
    fseek(pf,0,SEEK_END);
    int ret=ftell(pf);
    printf("文件的字节数%d\n",ret);
    rewind(pf);//文件指针就回到文件的起始位置了
    //等价于fseek(pf,0,SEEK_END);
    fputc('q',pf);
    
    fclose(pf);        
    pf=NULL;        
    return 0; 
} 

结果

在这里插入图片描述

7.⽂件读取结束的判定

7.1 被错误使⽤的 feof

牢记:在⽂件读取过程中,不能⽤feof函数的返回值直接来判断⽂件的是否结束。
feof 的作⽤是:当⽂件读取结束的时候,判断是读取结束的原因是否是遇到⽂件尾结束

1.⽂本⽂件读取是否结束,判断返回值是否为 EOF ( fgetc ),或者 NULL ( fgets )
例如:
• fgetc 判断是否为 EOF .
• fgets 判断返回值是否为 NULL .

2.⼆进制⽂件的读取结束判断,判断返回值是否⼩于实际要读的个数。
例如:
• fread判断返回值是否⼩于实际要读的个数。

⽂本⽂件的例⼦:

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    int c; // 注意:int,⾮char,要求处理EOF
    FILE* fp = fopen("test.txt", "r");
    if(!fp) 
    {
    perror("File opening failed");
    return EXIT_FAILURE;
	}
	//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);
}

⼆进制⽂件的例⼦:

#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);
}

8.⽂件缓冲区

ANSIC标准采⽤“缓冲⽂件系统”处理的数据⽂件的,所谓缓冲⽂件系统是指系统⾃动地在内存中为程序中每⼀个正在使⽤的⽂件开辟⼀块“⽂件缓冲区”。

从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才⼀起送到磁盘上。

如果从磁盘向计算机读⼊数据,则从磁盘⽂件中读取数据输⼊到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的⼤⼩根据C编译系统决定的。

缓冲分为:

1.完全缓冲

2.行缓冲(\n)

3.无缓冲

在这里插入图片描述

8.1 fflush

int fflush(FILE* stream);

功能

强行刷新参数stream指定流的缓冲区,确保数据写入底层设备

  • 对输出流:将缓冲区中未写入的数据立即写入文件
  • 对输入流:行为由具体实现决定,非C语言标准行为(可能清空输入缓冲区)
  • 参数为NULL时:刷新所有打开的输出流

参数

stream:指向文件流的指针(如stdout、文件指针等)

返回值

成功返回0,失败返回EOF

注意事项

1.仅对输出流或更新流(最后一次作为输出)有明确刷新行为

2.输入流的刷新行为不可移植(如清空输入缓冲区是非标准特性)

3.程序正常终止(exit)或调用fclose时会自动刷新,但程序崩溃时缓冲区数据可能丢失

代码演示

#include <stdio.h>
#include <windows.h>
//VS2022 WIN11环境测试
int main()
{
    FILE*pf = fopen("data.txt", "w");
    fputs("abcdef", pf);//先将代码放在输出缓冲区
    printf("睡眠10秒-已经写数据了,打开data.txt⽂件,发现⽂件没有内容\n");
    Sleep(10000);
    printf("刷新缓冲区\n");
    fflush(pf);//刷新缓冲区时,才将输出缓冲区的数据写到⽂件(磁盘)
    //注:fflush 在⾼版本的VS上不能使⽤了
    printf("再睡眠10秒-此时,再次打开data.txt⽂件,⽂件有内容了\n");
    Sleep(10000);
    //防止和fclose的作用混淆,先在10秒内看到结果,再关闭文件
    fclose(pf);
    //注:fclose在关闭⽂件的时候,也会刷新缓冲区
    pf = NULL;
    return 0;
}

这⾥可以得出⼀个结论:

因为有缓冲区的存在,C语⾔在操作⽂件的时候,需要做刷新缓冲区或者在⽂件操作结束的时候关闭⽂件。如果不做,可能导致读写⽂件的问题

9.更新文件

在这里插入图片描述

关键要点

1.在写完文件后,要继续读文件的时候,在读取之前一定要使用fflush()刷新文件缓冲区,或者使用fseek(),rewind()重新定位文件指示器的位置

2.在读完文件后,需要继续写文件之前,在写文件之前可以使用fseek(),rewind()重新定位文件指示器的位置

#include <stdio.h>  
int main () 
{         
    FILE * pf= fopen ( "text.txt" , "w+" );        
    if(pf==NULL)        
    {                
        perror("fopen");                
        return 1;        
    }  
    //写文件
    fputs("abcdefghi",pf);//文件内容此时在文件缓冲区
    fflush(pf);//刷新
    
    //读文件
    fseek(pf,0,SEEK_SET);//文件指示器在末尾,要重新定位
    int ch=fgetc(pf);
    printf("%c\n",ch);
    
    //想继续写文件将文件内容由abcdefghi改为abcxxxghi
    //文件指示器此时指向b
    fseek(pf,2,SEEK_CUR);
    fputs("xxx",pf);
    
    fclose(pf);
    pf=NULL;
    return 0;
}
内容概要:本文介绍了基于Matlab代码实现的【EI复现】考虑网络动态重构的分布式电源选址定容优化方法,重点研究在电力系统中结合网络动态重构技术进行分布式电源(如光伏、风电等)的最佳位置选择与容量配置的双层优化模型。该方法综合考虑配电网结构变化与电源布局之间的相互影响,通过优化算法实现系统损耗最小、电压稳定性提升及可再生能源消纳能力增强等多重目标。文中提供了完整的Matlab仿真代码与案例验证,便于复现实验结果并拓展应用于微网、储能配置与配电系统重构等相关领域。; 适合人群:电力系统、电气工程及其自动化等相关专业的研究生、科研人员及从事新能源规划与电网优化工作的工程师;具备一定Matlab编程基础优化理论背景者更佳。; 使用场景及目标:①用于科研论文复现,特别是EI/SCI级别关于分布式能源优化配置的研究;②支【EI复现】考虑网络动态重构的分布式电源选址定容优化方法(Matlab代码实现)撑毕业设计、课题项目中的电源选址定容建模与仿真;③辅助实际电网规划中对分布式发电接入方案的评估与决策; 阅读建议:建议结合提供的网盘资源下载完整代码与工具包(如YALMIP),按照文档目录顺序逐步学习,注重模型构建思路与代码实现细节的对应关系,并尝试在不同测试系统上调试与扩展功能。
本系统采用SpringBoot与Vue技术架构,实现了完整的影院票务管理解决方案,包含后台数据库及全套可执行代码。该系统在高等院校计算机专业毕业设计评审中获得优异评价,特别适用于正在进行毕业课题研究的学生群体,以及需要提升项目实践能力的开发者。同时也可作为课程结业作业或学期综合训练项目使用。 系统提供完整的技术文档经过全面测试的源代码,所有功能模块均通过多轮调试验证,保证系统稳定性可执行性。该解决方案可直接应用于毕业设计答辩环节,其技术架构符合现代企业级开发规范,采用前后端分离模式,后端基于SpringBoot框架实现业务逻辑数据处理,前端通过Vue.js构建用户交互界面。 系统核心功能涵盖影院管理、影片排期、座位预定、票务销售、用户管理等模块,实现了从影片上架到票务核销的完整业务流程。数据库设计遵循第三范式原则,确保数据一致性完整性。代码结构采用分层架构设计,包含控制器层、服务层、数据访问层等标准组,便于后续功能扩展维护。 该项目不仅提供了可直接部署运行的完整程序,还包含详细的技术实现文档,帮助开发者深入理解系统架构设计理念具体实现细节。对于计算机专业学生而言,通过研究该项目可以掌握企业级应用开发的全流程,包括需求分析、技术选型、系统设计测试部署等关键环节。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值