C语言教程——文件处理(2)

目录

前言

一、顺序读写函数(续)

1.1fprintf

1.2fscanf

1.3fwrite

1.4fread

二、流和标准流

2.1流

2.2标准流

2.3示例

三、sscanf和sprintf

3.1sprintf

3.2sscanf

四、文件的随机读写

4.1fseek

4.2ftell

4.3rewind

五、文件读取结束的判定

5.1feof相关判断知识

六、文件缓冲区

总结



前言

昨天最顺序读写函数了解了四个,今天接着学习。


一、顺序读写函数(续)

1.1fprintf

格式化输出函数

int fprintf ( FILE * stream, const char * format, ... );

第一个参数就是文件,第二个参数就是与printf的后面的参数一样。

我们可以用代码来掩饰一下:

我们先定义一个结构体变量:

struct S {char name[20];int age;int Id;
};

之后调用fprintf函数写入文件

struct S s = { "zhangsan",14,12345 };
fprintf(df,"%s %d %d\n",s.name,s.age,s.Id);

同样还是作用于之前的目标文件。

我们打开文件就可以看见,成功的运行了。

1.2fscanf

这里就是格式化读写文件

int fscanf ( FILE * stream, const char * format, ... );

通过fscanf就可以进行访问,一样的我们把创建一个结构体来接收:

FILE* df = fopen("D:\\project\\text.txt", "r");
struct S s = {0};
fscanf(df, "%s %d %d", s.name, &(s.age), &(s.Id));
printf("%s %d %d\n", s.name, s.age, s.Id);

之后就可以通过fscanf访问之前存入的数据,我们可以打印出来,然后运行一下看看:

我们可以看见,刚才访问的数据就实现了。

1.3fwrite

接着是二进制出入文件函数

size_t fwrite ( const void * ptr, size_t size, size_t count, FILE * stream );

第一个参数就是要传入的原始数据指针(因为不知道是什么类型,所以之类用void*类型表示),第二个是这个原始数据的大小,第三个是要传入文件的个数,最后一个就是要传入的文件。

我们可以用代码来演示:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>struct S {char name[20];int age;float score;
};int main()
{struct S s = { "李白",34,99.9 };//打开文件FILE* df = fopen("D:\\project\\text.txt", "wb");if (df == NULL){perror("fopen::");return 1;}//二进制写入fwrite(&s, sizeof(struct S), 1, df);//关闭文件fclose(df);df = NULL;return 0;
}

注意这里的方式改用了wb,因为它是为了输出数据,打开⼀个⼆进制⽂件,这里把结构体中的数据变为了二进制进行写入文件,我们可以打开文件看看:

这里发现变成了一堆不认识的东西,如果我们用二进制打开就可以看到:

这是一堆二进制,如果对二进制进行分析,就会得到一些数据。

1.4fread

二进制读取函数

size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );

我们发现这里的参数和二进制写入是一模一样的,所以话不多说,我们可以直接写入代码。

这里打开文件的方式改为‘rb’。

在代码之前我们可以看一下txt文件里是什么:

我们还不认识,接下来用fread来读取后输出,看看打印出来的是什么。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>struct S {char name[20];int age;float score;
};int main()
{struct S s = {0};//打开文件FILE* df = fopen("D:\\project\\text.txt", "rb");if (df == NULL){perror("fopen::");return 1;}//二进制读取fread(&s, sizeof(struct S), 1, df);printf("%s %d %f\n", s.name, s.age, s.score);//关闭文件fclose(df);df = NULL;return 0;
}

我们运行后:

发现是我们之前的数据,这里第三个数不一样的原因是因为我们使用的是浮点数进行输出,所以这里精度会出现偏差。

二、流和标准流

我们前面可以看到有流的概念,所以在这里再说一下流的概念。

2.1流

我们程序的数据需要输入到各种外部设备,也需要从外部设备中获得数据,不同的外部设备的输入输出操作各不相同,为了方便程序员对各种设备进行方便的操作,我们抽象出了流的概念,我们可以把流想成一条河,用的时候从里面拿,不用的时候可以还回去。

C程序针对文件、画面、键盘等的数据输入输出操作都是通过流操作的。一般情况下,我们想要向流里写数据,或者从流中读取数据,都是打开流,然后操作。

2.2标准流

C程序在启动的时候,默认启动了三个流,分别是:

stdin 标准输入流,在大多数的环境中从键盘输入,scanf函数就是从标准输入流中读取数据。

stdout 标准输出流,大多数的环境中输出至显示器界面,printf函数就是将信息输出到标准输出流中。

stderr 标准错误流,大多数环境中输出到显示器界面。

这是默认打开的三个流,我们使用scanf,printf等函数就可以直接进行输入输出函数的。

stdin、stdout、stderr三个流的类型是:FILE*,通常称为文件指针。

我们可以通过文件函数来访问流从而输入输出:

2.3示例

这里通过直接调用stdin从输入流读数据,完了显示到输出流中。

struct S {char name[20];int age;float score;
};int main()
{struct S s = { 0 };fscanf(stdin, "%s %d %f", s.name,&(s.age), &(s.score));fprintf(stdout, "%s %d %f\n", s.name, s.age, s.score);return 0;
}

运行一下我们可以看到:

这里实现了读取和输出。

我们也可以用fputc和fgetc来掩饰,十分的简单易懂:

int main()
{int c=fgetc(stdin);fputc(c, stdout);return 0;}

运行结果就是:

输入一个字符,输出一个字符

三、sscanf和sprintf

3.1sprintf

int sprintf ( char * str, const char * format, ... );

这个函数可以把后面的类型成员放到前面的字符串中。

返回值:成功后,将返回写入的字符总数。此计数不包括自动追加在字符串末尾的其他 null 字符。
失败时,将返回负数。

我们可以通过代码来理解:

struct S {char name[20];int age;float score;
};

首先我们先定义了一个结构体,然后通过后续操作把结构体中的成员按照原本的类型格式放到字符串中:

int main()
{struct S s = { "张三",39,99.99 };char arr[100] = { 0 };sprintf(arr, "%s %d %f", s.name, s.age, s.score);printf("%s\n", arr);return 0;
}

我们运行之后就可以看见:

确实按照原本的格式放到了arr字符串中。

3.2sscanf

int sscanf ( const char * s, const char * format, ...);

str是要读取的字符串,format是格式化字符串,...是根据格式化字符串提供的格式来指定要解析的数据类型和要存放数据的变量。

sscanf函数根据格式化字符串的格式,从字符串中提取数据,并将数据存入对应的变量中。它可以用来解析字符串中的数字、字符、字符串等数据,并将其存入变量中。

所以我们可以通过代码来实现一下,把上面字符串中的数据提取出来,然后放到一个新的结构体中:

int main()
{struct S s = { "张三",39,99.99 };char arr[100] = { 0 };sprintf(arr, "%s %d %f", s.name, s.age, s.score);printf("%s\n", arr);struct S s1 = {0};sscanf(arr, "%s %d %f", s1.name, &(s1.age), &(s1.score));printf("%s %d %f", s1.name, s1.age, s1.score);return 0;
}

这就实现了从字符串中提取,然后放到新的结构体中,我们打印新的结构体中的数据,就可以看见:

实现了新结构体的打印。

四、文件的随机读写

4.1fseek

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

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

这里第一个参数就是那个要访问的流,第二个是偏移量,第三个是选哪种方式,这里有三种方式。

ConstantReference position
SEEK_SETBeginning of file(文件开头)
SEEK_CURCurrent position of the file pointer(当前位置)
SEEK_ENDEnd of file *(文件结尾)

我们这里还用之前的文件,里面给上:

代码文件打开时,是指在a前面的。就可以通过代码来演示:

int main()
{FILE* df = fopen("D:\\project\\text.txt", "r");int ch = 0;ch=fgetc(df);printf("%c\n", ch);ch = fgetc(df);printf("%c\n", ch);ch = fgetc(df);printf("%c\n", ch);
}

这里通过fgetc来获取当前字符,函数使用一次那么指针就往后走一个。这时候运行就是:

我们如果想返回去访问之前的字符,那么就可以用fseek来实现,因为此时是在d前面,我们如果要访问下一个字符为b,如果定义的是当前位置,那么指针就需要往前2个位置,偏移量也就是-2:

printf("%c\n", ch);
fseek(df, -2, SEEK_CUR);
ch = fgetc(df);
printf("%c\n", ch);

我们通过运行就可以看到:

这就访问到了b。除了这一种方法还可以用另外两种,相对于开始b的偏移量就是1,相对于末尾b的偏移量就是-3,这样对参数进行赋值,那么就可以成功实现访问b。

但是如果我们不知道偏移量为多少,那么就可以用下面这个函数。

4.2ftell

返回当前指针位置

long int ftell ( FILE * stream );

传入文件指针,那么返回的就是一个整形,这个整形就是文件指针当前指向的位置。 

这里针对之前的代码:

printf("%d\n", ftell(df));

结果显示的就是2. 

4.3rewind

将指针返回到开始,起始位置。

void rewind ( FILE * stream );

这里也是针对之前的代码: 

rewind(df);
printf("%d\n", ftell(df));

 结果就是0.

还有很多的函数,感兴趣的可以自己看看。

五、文件读取结束的判定

5.1feof相关判断知识

在文件读取的过程中,不能使用feof函数的返回值直接用来判断文件的是否结束。而是应用于当文件结束的时候,判断文件是否遇到文件结尾结束。

1.文本文件读取是否结束:

fgetc判断结束是否为EOF,返回失败返回EOF

fgets判断结束是否为NULL,返回失败是返回一个空指针

2.二进制文件的读取结束判断:

fread判断返回值是否小于实际要读的个数

文件读取结束了,结束后想知道结束的原因:

feof返回为真的话,就说明是文件正常读取到了结束标志而结束的。

ferror返回为真的话,就说明文件在读取过程中出错了而结束的。

六、文件缓冲区

文件缓冲区是在计算机系统中用来临时存放文件数据的一块内存区域。当计算机需要读取或写入文件数据时,通常会先将数据读取到文件缓冲区中,然后再根据需要将数据从缓冲区移动到内存或磁盘中。

文件缓冲区的存在可以提高文件读写的效率。由于磁盘操作相对较慢,每次读写都需要进行磁盘寻址,而将数据读取到缓冲区中可以避免频繁的磁盘操作。当数据写入缓冲区时,系统可以选择将数据缓存一段时间后再进行实际的写入操作,从而避免频繁的磁盘写入。

文件缓冲区一般由操作系统提供,可以是内核级别的缓冲区或用户级别的缓冲区。内核级别的缓冲区由操作系统管理,对于用户程序来说是透明的;而用户级别的缓冲区由程序员自己管理,可以根据需要进行灵活的控制。

使用文件缓冲区需要注意及时刷新缓冲区和关闭文件。当数据写入缓冲区后,如果不及时刷新缓冲区,数据可能不会立即写入磁盘中;而关闭文件时,系统会自动将缓冲区中的数据写入磁盘。

总之,文件缓冲区是一种提高文件读写效率的技术,可以有效减少磁盘操作次数,提高系统性能。

ANSIC 标准采⽤“缓冲⽂件系统” 处理的数据⽂件的,所谓缓冲⽂件系统是指系统⾃动地在内存中为程序中每⼀个正在使⽤的⽂件开辟⼀块“⽂件缓冲区”。从内存向磁盘输出数据会先送到内存中的缓冲区,装满缓冲区后才⼀起送到磁盘上。如果从磁盘向计算机读⼊数据,则从磁盘⽂件中读取数据输⼊到内存缓冲区(充满缓冲区),然后再从缓冲区逐个地将数据送到程序数据区(程序变量等)。缓冲区的⼤⼩根据C编译系统决定的。

因为有缓冲区的存在,C语⾔在操作⽂件的时候,需要做刷新缓冲区或者在⽂件操作结束的时候关闭⽂件


总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

建表注意事项(2):表约束,主键自增,序列[oracle]

没有明确写明数据库时,默认基于oracle 约束的分类 用于确保数据的完整性和一致性。约束可以分为 表级约束 和 列级约束&#xff0c;区别在于定义的位置和作用范围 复合主键约束: 主键约束中有2个或以上的字段 复合主键的列顺序会影响索引的使用&#xff0c;需谨慎设计 添加…

线性回归的损失和优化02

线性回归的损失和优化 学习目标 知道线性回归中损失函数知道使用正规方程对损失函数优化的过程知道使用梯度下降法对损失函数优化的过程 假设刚才的房子例子&#xff0c;真实的数据之间存在这样的关系&#xff1a; 真实关系&#xff1a; 真实房子价格 0.02中心区域的距离 0.…

年化18%-39.3%的策略集 | backtrader通过xtquant连接qmt实战

原创内容第785篇&#xff0c;专注量化投资、个人成长与财富自由。 大年初五&#xff0c;年很快就过完了。 其实就是本身也只是休假一周&#xff0c;但是我们赋予了它太多意义。 周五咱们发布发aitrader v4.1&#xff0c;带了backtraderctp期货的实盘接口&#xff1a; aitra…

【数据结构】_链表经典算法OJ(力扣/牛客第二弹)

目录 1. 题目1&#xff1a;返回倒数第k个节点 1.1 题目链接及描述 1.2 解题思路 1.3 程序 2. 题目2&#xff1a;链表的回文结构 2.1 题目链接及描述 2.2 解题思路 2.3 程序 1. 题目1&#xff1a;返回倒数第k个节点 1.1 题目链接及描述 题目链接&#xff1a; 面试题 …

成绩案例demo

本案例较为简单&#xff0c;用到的知识有 v-model、v-if、v-else、指令修饰符.prevent .number .trim等、computed计算属性、toFixed方法、reduce数组方法。 涉及的功能需求有&#xff1a;渲染、添加、删除、修改、统计总分&#xff0c;求平均分等。 需求效果如下&#xff1a…

git基础使用--4---git分支和使用

文章目录 git基础使用--4---git分支和使用1. 按顺序看2. 什么是分支3. 分支的基本操作4. 分支的基本操作4.1 查看分支4.2 创建分支4.3 切换分支4.4 合并冲突 git基础使用–4—git分支和使用 1. 按顺序看 -git基础使用–1–版本控制的基本概念 -git基础使用–2–gti的基本概念…

Kafka下载

一、Kafka下载 下载地址&#xff1a;https://kafka.apache.org/downloads 二、Kafka安装 因为选择下载的是 .zip 文件&#xff0c;直接跳过安装&#xff0c;一步到位。 选择在任一磁盘创建空文件夹&#xff08;不要使用中文路径&#xff09;&#xff0c;解压之后把文件夹内容…

nodejs:express + js-mdict 网页查询英汉词典,能播放声音

向 DeepSeek R1 提问&#xff1a; 我想写一个Web 前端网页&#xff0c;后台用 nodejs js-mdict, 实现在线查询英语单词 1. 项目结构 首先&#xff0c;创建一个项目目录&#xff0c;结构如下&#xff1a; mydict-app/ ├── public/ │ ├── index.html │ ├── st…

【自开发工具介绍】SQLSERVER的ImpDp和ExpDp工具01

1、开发背景 大家都很熟悉&#xff0c;Oracle提供了Impdp和ExpDp工具&#xff0c;功能很强大&#xff0c;可以进行db的导入导出的处理。但是对于Sqlserver数据库只是提供了简单的图形化的导出导入工具&#xff0c;在实际的开发和生产环境不太可能让用户在图形化的界面选择移行…

【Block总结】完全注意力Fully Attentional,同时捕捉空间和通道的注意力|即插即用

论文信息 标题: Fully Attentional Network for Semantic Segmentation论文链接: https://arxiv.org/pdf/2112.04108GitHub链接: https://github.com/maggiesong7/FullyAttentional 创新点 全注意力模块&#xff08;FLA&#xff09;: 该模块能够在一个相似性图中同时捕捉空…

强化学习、深度学习、深度强化学习的区别是什么?

前言 深度强化学习就是 深度学习 和 强化学习 的结合体。它让计算机程序&#xff08;也就是智能体&#xff09;在特定环境中不断尝试&#xff0c;从错误中学习&#xff0c;最终找到最优的行动策略。 深度学习是AlphaGo从棋谱里学习&#xff0c;强化学些Alphazero 学习规则&am…

99.20 金融难点通俗解释:中药配方比喻马科维茨资产组合模型(MPT)

目录 0. 承前1. 核心知识点拆解2. 中药搭配比喻方案分析2.1 比喻的合理性 3. 通俗易懂的解释3.1 以中药房为例3.2 配方原理 4. 实际应用举例4.1 基础配方示例4.2 效果说明 5. 注意事项5.1 个性化配置5.2 定期调整 6. 总结7. 代码实现 0. 承前 本文主旨&#xff1a; 本文通过中…

笔灵ai写作技术浅析(四):知识图谱

知识图谱(Knowledge Graph)是一种结构化的知识表示方式,通过将知识以图的形式进行组织,帮助AI系统更好地理解和利用信息。在笔灵AI写作中,知识图谱技术被广泛应用于结构化组织各种领域的知识,使AI能够根据写作主题快速获取相关的背景知识、概念关系等,从而为生成内容提供…

基于python的Kimi AI 聊天应用

因为这几天deepseek有点状况&#xff0c;导致apikey一直生成不了&#xff0c;用kimi练练手。这是一个基于 Moonshot AI 的 Kimi 接口开发的聊天应用程序&#xff0c;使用 Python Tkinter 构建图形界面。 项目结构 项目由三个主要Python文件组成&#xff1a; 1. main_kimi.py…

python算法和数据结构刷题[5]:动态规划

动态规划&#xff08;Dynamic Programming, DP&#xff09;是一种算法思想&#xff0c;用于解决具有最优子结构的问题。它通过将大问题分解为小问题&#xff0c;并找到这些小问题的最优解&#xff0c;从而得到整个问题的最优解。动态规划与分治法相似&#xff0c;但区别在于动态…

JavaFX - 3D 形状

在前面的章节中&#xff0c;我们已经了解了如何在 JavaFX 应用程序中的 XY 平面上绘制 2D 形状。除了这些 2D 形状之外&#xff0c;我们还可以使用 JavaFX 绘制其他几个 3D 形状。 通常&#xff0c;3D 形状是可以在 XYZ 平面上绘制的几何图形。它们由两个或多个维度定义&#…

wax到底是什么意思

在很久很久以前&#xff0c;人类还没有诞生文字之前&#xff0c;人类就产生了语言&#xff1b;在诞生文字之前&#xff0c;人类就已经使用了语言很久很久。 没有文字之前&#xff0c;人们的语言其实是相对比较简单的&#xff0c;因为人类的生产和生活水平非常低下&#xff0c;…

从理论到实践:Linux 进程替换与 exec 系列函数

个人主页&#xff1a;chian-ocean 文章专栏-Linux 前言&#xff1a; 在Linux中&#xff0c;进程替换&#xff08;Process Substitution&#xff09;是一个非常强大的特性&#xff0c;它允许将一个进程的输出直接当作一个文件来处理。这种技术通常用于Shell脚本和命令行操作中…

Python 中最大堆和最小堆的构建与应用:以寻找第 k 大元素为例

引言 在数据处理和算法设计中&#xff0c;堆&#xff08;Heap&#xff09;是一种非常重要的数据结构。它是一种特殊的完全二叉树&#xff0c;具有高效的插入和删除操作特性&#xff0c;时间复杂度为 O ( log ⁡ n ) O(\log n) O(logn)。堆主要分为最大堆和最小堆&#xff0c;…

使用Avalonia UI实现DataGrid

1.Avalonia中的DataGrid的使用 DataGrid 是客户端 UI 中一个非常重要的控件。在 Avalonia 中&#xff0c;DataGrid 是一个独立的包 Avalonia.Controls.DataGrid&#xff0c;因此需要单独通过 NuGet 安装。接下来&#xff0c;将介绍如何安装和使用 DataGrid 控件。 2.安装 Dat…