考研C语言复习进阶(5)

news2025/1/11 14:23:50

目录

1. 为什么使用文件

2. 什么是文件

2.1 程序文件

2.2 数据文件

2.3 文件名

3. 文件的打开和关闭

3.1 文件指针

3.2 文件的打开和关闭

 4. 文件的顺序读写

​编辑

​编辑

 4.1 对比一组函数:

​编辑 5. 文件的随机读写

5.1 fseek

 5.2 ftell

5.3 rewind

6. 文本文件和二进制文件

 7. 文件读取结束的判定

7.1 被错误使用的feof

8. 文件缓冲区


1. 为什么使用文件

我们前面学习结构体时,写了通讯录的程序,当通讯录运行起来的时候,可以给通讯录中增加、删除数据,此时数据是存放在内存中,当程序退出的时候,通讯录中的数据自然就不存在了,等下次运行通讯录程序的时候,数据又得重新录入,如果使用这样的通讯录就很难受。
我们在想既然是通讯录就应该把信息记录下来,只有我们自己选择删除数据的时候,数据才不复存在。
这就涉及到了数据持久化的问题,我们一般数据持久化的方法有,把数据存放在磁盘文件、存放到数据库等方式。
使用文件我们可以将数据直接存放在电脑的硬盘上,做到了数据的持久化。

2. 什么是文件

磁盘上的文件是文件。
但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件(从文件功能的角度来分类的)。

2.1 程序文件


包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境
后缀为.exe)。


2.2 数据文件


文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,
或者输出内容的文件。
本章讨论的是数据文件。
在以前各章所处理数据的输入输出都是以终端为对象的,即从终端的键盘输入数据,运行结果显示到显示器上。

其实有时候我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理的就是磁盘上文件。


2.3 文件名


一个文件要有一个唯一的文件标识,以便用户识别和引用。
文件名包含3部分:文件路径+文件名主干+文件后缀
例如: c:\code\test.txt
为了方便起见,文件标识常被称为文件名。

3. 文件的打开和关闭


3.1 文件指针


缓冲文件系统中,关键的概念是“文件类型指针”,简称“文件指针”。
每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统声明的,取名FILE.
例如,VS2013编译环境提供的 stdio.h 头文件中有以下的文件类型申明: 

struct _iobuf {
    char *_ptr;
    int  _cnt;
    char *_base;
    int  _flag;
    int  _file;
    int  _charbuf;
    int  _bufsiz;
    char *_tmpfname;
   };
typedef struct _iobuf FILE;

或者 

不同的C编译器的FILE类型包含的内容不完全相同,但是大同小异。
每当打开一个文件的时候,系统会根据文件的情况自动创建一个FILE结构的变量,并填充其中的信息,使用者不必关心细节。
一般都是通过一个FILE的指针来维护这个FILE结构的变量,这样使用起来更加方便。
下面我们可以创建一个FILE*的指针变量: 

FILE* pf;//文件指针变量

定义pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区中的信息就能够访问该文件。也就是说,通过文件指针变量能够找到与它关联的文件。
比如: 

 

3.2 文件的打开和关闭


文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。
在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指针和文件的关系。
ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件。 

//打开文件
FILE * fopen ( const char * filename, const char * mode );
//关闭文件
int fclose ( FILE * stream );

打开方式如下:

文件使用方式                 含义                                                                 如果指定文件不存在
“r”(只读) 为了输入数据,打开一个已经存在的文本文件                                 出错
“w”(只写) 为了输出数据,打开一个文本文件                                         建立一个新的文件
“a”(追加) 向文本文件尾添加数据                                                            建立一个新的文件
“rb”(只读) 为了输入数据,打开一个二进制文件                                             出错
“wb”(只写) 为了输出数据,打开一个二进制文件                                   建立一个新的文件
“ab”(追加) 向一个二进制文件尾添加数据                                                       出错
“r+”(读写) 为了读和写,打开一个文本文件                                                    出错
“w+”(读写) 为了读和写,建议一个新的文件                                         建立一个新的文件
“a+”(读写) 打开一个文件,在文件尾进行读写                                      建立一个新的文件
“rb+”(读写) 为了读和写打开一个二进制文件                                                  出错
“wb+”(读写) 为了读和写,新建一个新的二进制文件                           建立一个新的文件
“ab+”(读写) 打开一个二进制文件,在文件尾进行读和写                     建立一个新的文件

实例代码:

/* fopen fclose example */
#include <stdio.h>
int main ()
{
 FILE * pFile;
 //打开文件
 pFile = fopen ("myfile.txt","w");
 //文件操作
 if (pFile!=NULL)
{
  fputs ("fopen example",pFile);
  //关闭文件
  fclose (pFile);
}
 return 0;
}

 4. 文件的顺序读写

功能                                                 函数名                                                  适用于
字符输入函数                                   fgetc                                                 所有输入流
字符输出函数                                   fputc                                                 所有输出流
文本行输入函数                               fgets                                                 所有输入流
文本行输出函数                               fputs                                                 所有输出流
格式化输入函数                               fscanf                                               所有输入流
格式化输出函数                               fprintf                                                 所有输出流
二进制输入                                      fread                                                 文件
二进制输出                                      fwrite                                                 文件

 

 

 

 

fprintf和fscanf 后面的参数是可变参数列表。

 

 

 4.1 对比一组函数:


scanf/fscanf/sscanf
printf/fprintf/sprintf
这里演示讲解这句函数的使用和对比

sprintf和sscanf使用:

 5. 文件的随机读写


5.1 fseek


根据文件指针的位置和偏移量来定位文件指针。

 

例子:

SEEK_CUR是pf当前位置

SEEK_SET是pf起始位置 

 5.2 ftell


返回文件指针相对于起始位置的偏移量

 

5.3 rewind


让文件指针的位置回到文件的起始位置

 

6. 文本文件和二进制文件


根据数据的组织形式,数据文件被称为文本文件或者二进制文件。
数据在内存中以二进制的形式存储,如果不加转换的输出到外存,就是二进制文件。
如果要求在外存上以ASCII码的形式存储,则需要在存储前转换。以ASCII字符的形式存储的文件就是文本文件。
一个数据在内存中是怎么存储的呢?
字符一律以ASCII形式存储,数值型数据既可以用ASCII形式存储,也可以使用二进制形式存储。
如有整数10000,如果以ASCII码的形式输出到磁盘,则磁盘中占用5个字节(每个字符一个字节),而二进制形式输出,则在磁盘上只占4个字节(VS2013测试) 

小端存储:

#include <stdio.h>
int main()
{
int a = 10000;
FILE* pf = fopen("test.txt", "wb");
fwrite(&a, 4, 1, pf);//二进制的形式写到文件中
fclose(pf);
pf = NULL;
return 0;
}

 7. 文件读取结束的判定


7.1 被错误使用的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编译系统决定的。 

 

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

这里可以得出一个结论:
因为有缓冲区的存在,C语言在操作文件的时候,需要做刷新缓冲区或者在文件操作结束的时候关闭文件。
如果不做,可能导致读写文件的问题。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1520015.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

微信小程序--分享如何与ibeacon蓝牙信标建立联系

ibeacon蓝牙设备 iBeacon是苹果公司2013年9月发布的移动设备用OS&#xff08;iOS7&#xff09;上配备的新功能。其工作方式是&#xff0c;配备有 低功耗蓝牙&#xff08;BLE&#xff09;通信功能的设备使用BLE技术向周围发送自己特有的ID&#xff0c;接收到该ID的应用软件会根…

【JAVA基础】API:Math、System、runtime、object、BigInteger 、BigDecima、爬虫、分组、时间类、包装类

1.Math 2.System public class Main {public static void main(String[] args) {int[] arr {1, 2, 3, 4, 5, 6, 7, 8};int[] arr1 new int[8];System.arraycopy(arr,0,arr1,1,5); // 从1970.1.1开始到现在的毫秒形式long l1 System.currentTimeMillis();//171046475…

微信小程序将高德地图转为腾讯地图的自行车路线规划

微信小程序后台首页开发设置 相关文档 腾讯后台 微信小程序接入JDK JDK腾讯地图文档 腾讯路线规划文档 核心代码 <map id"myMap" ref"myMap" style"width: 100%; height: calc(100vh - 80px)":latitude"latitude" :scale&qu…

畅捷通T+ InitServerInfo.aspx SQL漏洞(2024年3月发布)

漏洞简介 由于畅捷通T的InitServerInfo.aspx接口处未对用户的输入进行过滤和校验&#xff0c;未经身份验证的攻击者除了可以利用 SQL 注入漏洞获取数据库中的信息&#xff08;例如&#xff0c;管理员后台密码、站点的用户个人信息&#xff09;之外&#xff0c;甚至在高权限的情…

uniapp 跳转返回携带参数(超好用)

天梦星服务平台 (tmxkj.top)https://tmxkj.top/#/ 1.返回界面 uni.$emit(enterPeople, this.entryList)uni.navigateBack({delta: 1}) 2.返回到的界面&#xff08;接收数据界面&#xff09; onShow() {let that thisuni.$on(enterPeople,function(enterPeopledata){console.…

2024三掌柜赠书活动第十七期:数据结构与算法(Rust语言描述)

目录 目录 前言 数据结构的选择 常见算法实现 实际应用 关于《数据结构与算法&#xff08;Rust语言描述&#xff09;》 编辑推荐 作者简介 图书目录 书中前言/序言 《数据结构与算法&#xff08;Rust语言描述&#xff09;》全书速览 结束语 前言 作为开发者&#x…

Dev C++和Visual Studio Code哪个好?

Dev C和Visual Studio Code哪个好&#xff1f; Dev C和Visual Studio Code都是常用的集成开发环境&#xff08;IDE&#xff09;&#xff0c;用于编写和调试代码。它们各自有不同的优点和适用场景。 在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「C的资…

stm32-定时器输入捕获

目录 一、输入捕获简介 二、输入捕获框图 1.定时器总框图 2.输入捕获框图 3.主从触发模式 三、固件库实现 1.定时器测量PWM频率 2.PWMI模式 一、输入捕获简介 二、输入捕获框图 1.定时器总框图 上图可知&#xff0c;四个输入捕获和输出比较共用4个CCR寄存器&#x…

基于SpringBoot和Echarts的全国地震可视化分析实战

目录 前言 一、后台数据服务设计 1、数据库查询 2、模型层对象设计 3、业务层和控制层设计 二、Echarts前端配置 1、地图的展示 2、次数排名统计 三、最终结果展示 1、地图展示 2、图表展示 总结 前言 在之前的博客中基于SpringBoot和PotsGIS的各省地震震发可视化分…

【C++】类的默认成员函数及其特性(万字详解)

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:C ⚙️操作环境:Visual Studio 2022 目录 类对象函数的核心设计----This指针 This指针是什么? This指针的特性 类的默认成员函数 构造函数 构造函数的定义 构造函数的特性 析构函数 析构函数概念 析构函数的特…

.NET开源快速、强大、免费的电子表格组件

今天大姚给大家分享一个.NET开源&#xff08;MIT License&#xff09;、快速、强大、免费的电子表格组件&#xff0c;支持数据格式、冻结、大纲、公式计算、图表、脚本执行等。兼容 Excel 2007 (.xlsx) 格式&#xff0c;支持WinForm、WPF和Android平台&#xff1a;ReoGrid。 项…

【Hadoop】Hadoop概述与核心组件

目录 Hadoop概述Hadoop 发展历史Hadoop 三大发行版本1.Apache Hadoop&#xff08;常用&#xff09;2.Cloudera Hadoop3.Hortonworks Hadoop优势优势总结——4高&#xff08;高可靠、高扩展、高效、高容错&#xff09; Hadoop组成1.HDFS管理者&#xff1a;NameNode&#xff08;n…

分布式CAP理论

CAP理论&#xff1a;一致性&#xff08;Consistency&#xff09;、可用性&#xff08;Availability&#xff09;和分区容错性&#xff08;Partition tolerance&#xff09;。是Eric Brewer在2000年提出的&#xff0c;用于描述分布式系统基本性质的定理。这三个性质在分布式系统…

贪心算法(算法竞赛、蓝桥杯)--均分纸牌

1、B站视频链接&#xff1a;A30 贪心算法 P1031 [NOIP2002 提高组] 均分纸牌_哔哩哔哩_bilibili 题目链接&#xff1a;[NOIP2002 提高组] 均分纸牌 - 洛谷 #include <bits/stdc.h> using namespace std; int n,a[101],av,cnt;int main(){scanf("%d",&n);…

Android SystemServer进程解析

SystemServer进程在android系统中占了举足轻重的地位&#xff0c;系统的所有服务和SystemUI都是由它启动。 一、SystemServer进程主函数流程 1、主函数三部曲 //frameworks/base/services/java/com/android/server/SystemServer.java /** * The main entry point from zy…

鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:Navigator)

路由容器组件&#xff0c;提供路由跳转能力。 说明&#xff1a; 该组件从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 子组件 可以包含子组件。 接口 Navigator(value?: {target: string, type?: NavigationType}) …

从0开始回顾MySQL --- 三范式与表设计

什么是数据库设计三范式 数据库表设计的原则。教你怎么设计数据库表有效&#xff0c;并且节省空间。 三范式 第一范式&#xff1a;任何一张表都应该有主键&#xff0c;每个字段是原子性的不能再分 以下表的设计不符合第一范式&#xff1a;无主键&#xff0c;并且联系方式可拆…

信雅纳网络测试的二次开发集成:XOA(Xena Open-Source Automation)开源自动化测试

目录 XOA是什么 XOA CLI XOA Python API ​XOA Python Test Suite/测试套件 XOA Converter Source Code XOA是什么 XOA&#xff08;Xena Open-Source Automation&#xff09;是一个开源的测试自动化框架&#xff0c;追求“高效、易用、灵活”的跨操作系统的开发框架。能…

量子遗传算法优化VMD参数,五种适应度函数任意切换,最小包络熵、样本熵、信息熵、排列熵、排列熵/互信息熵...

关于量子遗传算法&#xff0c;在众多文献均有应用。下面简述一下原理。 &#xff08;1&#xff09;量子比特编码 子遗传算法通过引入量子比特来完成基因的存储和表达。量子比特是量子信息中的概念&#xff0c;它与经典比特不同&#xff0c;是因为它可以在同一时刻处于两个状态的…

Docker安装蜜罐Hfish

前言 无意中发现公司的一台服务器被爆破&#xff0c;修改了密码&#xff0c;为了确定内网是否安装需要搭建一个蜜罐来看一下是否存在隐患。 如何安装Docker&#xff0c;请查看我另一篇文章 https://blog.csdn.net/l1677516854/article/details/136751211 一、拉取镜像 dock…