速通C语言第十二站 文件操作

系列文章目录

 速通C语言系列

 速通C语言第一站 一篇博客带你初识C语言        http://t.csdn.cn/N57xl

 速通C语言第二站 一篇博客带你搞定分支循环   http://t.csdn.cn/Uwn7W

 速通C语言第三站  一篇博客带你搞定函数        http://t.csdn.cn/bfrUM

速通C语言第四站  一篇博客带你学会数组          http://t.csdn.cn/Ol3lz

 速通C语言第五站 一篇博客带你详解操作符      http://t.csdn.cn/OOUBr

速通C语言第六站 一篇博客带你掌握指针初阶   http://t.csdn.cn/7ykR0

速通C语言第七站 一篇博客带你掌握数据的存储 http://t.csdn.cn/qkerU

 速通C语言第八站 一篇博客带你掌握指针进阶    http://t.csdn.cn/m95FK

 速通C语言第八.五站 指针进阶题目练习           http://t.csdn.cn/wWC2x

速通C语言第九站  字符相关函数及内存函数    http://t.csdn.cn/YyBBM

 速通C语言第十站  自定义类型                          http://t.csdn.cn/jsGJ7

速通C语言第十一站  动态内存开辟                  http://t.csdnimg.cn/necjp

感谢佬们支持!首先祝大家元旦快乐!


文章目录

  • 系列文章目录
  • 前言
  • 1、为什么使用文件
  • 2、什么是文件
  •          文件名
  • 3、文件的打开和关闭
  • 4、文件的顺序读写
  •        流
  •        一次读一个
  •        一次读一行
  •        格式化输入输出函数
  •        二进制输入输出函数
  •        综合对比
  • 5、文件的随机读写
  • 6、文本文件和二进制文件
  • 7、文件读取结束的判定
  • 8、文件缓冲区
  • 总结

前言

   在学习之前,我家首先要知道,文件/文件系统是一个很重要的东西,而且研究文件只停留在语言层面是非常片面的。等我们学到操作系统后,才会对此有一个更深的理解.


1、为什么使用文件

比如说我们写一个通讯录,运行之后进行增删查改,但是退出程序后我们的数据就没了

要想有信息拷贝,就要把数据写到文件中。


2、什么是文件

文件分为两种,一种为数据文件,另一种为程序文件(内存文件)

程序文件分为3种 :1、我们写的.c文件

                                2、编译过程中产生的临时文件 .i ,.s .o

                                3、最后生成的可执行程序 .exe

而数据文件简单来说就是我们能从这个文件中读点数据,也能将程序中的文件写到文件中


文件名

    一个文件需要一个唯一的文件标识符,在我们看来是文件名(但是在操作系统看来不是)

文件名由三部分构成

 文件路径+文件名+后缀(注:在Linux系统中文件后缀没用)

例:

C:\code\test.txt


而文件的路径分为两种

一种叫绝对路径,表示从根目录一直到你当前文件的路径

例如/c/Users/86138/tDesktop/test.c 

还有一种叫相对路径,可以表示当前路径或上级路径的文件

比如test.c  ../test.c


3、文件的打开和关闭

每一个被打开的文件都在内存中用一个结构体维护,用于存放文件的部分信息(如文件存放的位置,文件的状态信息等),这个结构体被typedef为FILE

所以我们要想对这个文件做什么,就要用文件指针FILE*调用

关闭一个文件,我们用fclose函数

如果关闭成功,返回0,失败返回EOF


打开一个文件,我们用fopen函数

其中,第一个参数为文件的名字,第二个参数为打开文件的方式,有6种选项选择(我们重点研究前三个)

如果打开成功,返回一个文件指针,失败就返回NULL

我们写一波代码给大家看一下

我们先以 写 打开一个文件,用“w"选项,

意为,如果文件存在,会先清空再打开,如果不存在,会创建出来

FILE* pf = fopen("test.txt", "w");if (pf == NULL){printf("打开失败\n");}//写文件//关文件fclose(pf);pf = NULL;

运行之后打开代码所在的目录

(果然多了一个test.txt)


写了之后我们在读一个文件

FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("fopen\n");}

读和写不同,如果没有该文件,会直接报错(使用perror函数)



4、文件的顺序读写

我们先来补充一个流的概念,流的概念很抽象,我们在没学操作系统之前,只能稍微理解一下

众所周知,我们储存一个程序文件有很多硬件来选择,比如屏幕(屏幕显示文件的本质也是存储),硬盘,U盘,网络

所以选择很多,不同选择的读写方式肯定不同,而在软件层面要考虑所有选择的读写方式显然太SB了,所以我们抽象一个“流”的概念出来,其类型为FILE*

我们在写文件的时候向流中写,剩下向右边的东西怎么写是操作系统的事,他会以多态的方式实现一系列方法,这些都是以后再学的啦


另外,当C语言程序运行起来,就默认打开了3个流

0   stdin (标准输入流)   对应得硬件是键盘

1   stdout(标准输出流)  对应得硬件是屏幕

2   stderr(标准输出错误流)  对应得硬件也是屏幕


一次读一个

我们用fputc/fgetc可以从指定流中输出/输入一个数据

我们尝试向标准输出stdout(显示器)输出3个字母

fputc('z', stdout);fputc('y', stdout);fputc('g', stdout);


再尝试从标准输入stdin中读几个字符

既然我们能从stdout,stdin里读写,那么文件也可以

创建一个test.txt

FILE* pf = fopen("test.txt", "w");//写fputc('a', pf);fputc('b', pf);fputc('c', pf);

 查看一下test.txt

 (成功)

再读

FILE* pf = fopen("test.txt", "r");int ret = fgetc(pf);printf("%c\n", ret);

第二次读


一次读一行

一次读写一个字符,太慢了

由此我们提供fgets读一行,fputs写一行

 

注意:num代表读取的最大个数,如果num=100,则实际读99个,因为要预留一个\0的位置

(因为无论如何这都是在语言的层面读写,就要遵守语言的规则以\0结尾)

另外,如果某一行的大小+1(\0的大小)<num,那就只读这一行,不读下一行

例:

FILE* pf = fopen("test.txt", "w");fputs("abc\n", pf);fputs("qwe\n", pf);fclose(pf);pf = NULL;

打开文件

FILE* pf = fopen("test.txt", "r");char arr[10] = { 0 };fgets(arr, 4, pf);printf("%s\n", arr);

先读4个,发现只读了第一行

fgets(arr, 5, pf);printf("%s\n", arr);

 改成读5个,他依然只读第一行


格式化输入输出函数

fprintf

fscanf

const char* format是我要输的格式,就和我们学的printf,scanf一样

例:

struct S{char arr[10];int num;float sc;};struct S s = { "abcdef",10,5.5};FILE* pf = fopen("test.txt", "w");if (pf == NULL){perror("fopen");}fprintf(pf, "%s %d %f",s.arr,s.num,s.sc);


二进制输入输出函数

fread

从流中读count个size大小的数据到buffer中

fwrite

把buffer中count个size大小的数据写入buffer中

例:

struct S{char arr[10];int num;float sc;};struct S s = { "abcdef",10,5.5 };FILE* pf = fopen("test.txt", "wb");//二进制写,wbif (pf == NULL){perror("fopen\n");}fwrite(&s, sizeof(struct S), 1, pf);

字符串从二进制写进去还是一样,但是数字不行,我们看不懂

我们看不懂,但是fread可以

struct S s = {0 };FILE* pf = fopen("test.txt", "rb");//二进制读,rbfread(&s, sizeof(struct S), 1, pf);printf("%s %d %f", &s.arr, s.num, s.sc);

读一下

struct S{char arr[10];int num;float sc;};struct S s = { 0};FILE* pf = fopen("test.txt", "r");if (pf == NULL){perror("fopen");}fscanf(pf, "%s %d %f",s.arr,&(s.num),&(s.sc));//记得加&printf("%s %d %f", s.arr, s.num, s.sc);


综合对比

我们再补充一个sscanf和sprintf,

 从一个字符串中读取一个格式化的数据,其中,format代表格式

再加上我们熟悉的scanf和fscanf

scanf,从标准输入stdin(键盘)输入格式化的语句

针对所有输出流的格式化输入语句,其中输出流包括stdin和文件,也就是说scanf是fscanf的子集

	fscanf(0,const char* format...)//等价于scanf

 把一个字符串中转换一个格式化的数据,其中,format代表格式

printf,针对标准输出stdout(显示器) 的格式化输出语句

 

 fprintf,针对所有输出流 的格式化输出语句,同上,标准输出流包括stdout和文件

		fprintf(1, const char* format...)//等价于printf

5、文件的随机读写

随机读写意为想读哪读哪

之前我们学的顺序读写只能从开头往下一个一个读,有了随机读写,我们可以从任意地方开始读。

第二个参数表示偏移量

第三个参数表示起始位置,有三种选择

SEEK_CUR 当前文件指针的位置

SEEK_END 文件末,此时偏移量只能为负,即从后向前读(但是其封装的系统调用lseek中为可正可负,会对文件相应扩容,并产生文件空洞等,此处可以忽略)

SEEK_SET  文件开始,此时偏移量只能为正,即从头开始读

我们写个代码来用一下这个函数

先将我们的test.txt中写上abcdef

FILE* pf = fopen("test.txt", "r");int ch = fgetc(pf);printf("%c\n", ch);//ach = fgetc(pf);printf("%c\n", ch);//bch = fgetc(pf);printf("%c\n", ch);//c

显然,再往下读就是d了,现在我们又想读b了,怎么办?调整一下文件指针,往前推两个

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

(又读到b了,牛逼)


与之补充的还有两个函数

ftell

可以返回我们当前文件的偏移量

例:

(我们当前读完了b,要读c,所以偏移量为2)


rewind

让文件指针的位置又回到文件开始

例:

printf("文件的偏移量为:%d\n", ftell(pf));rewind(pf);printf("文件的偏移量为:%d\n", ftell(pf));


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

根据数据得组织形式,数据文件被称为文本文件/二进制文件

二进制文件:数据在内存中以二进制形式储存,如果不加转换得输出到外存,就是二进制文件

文本文件:如果要求在外存上以ASCII码的形式存储,则需要在存储前转换以ASCII码的形式存储的文件就是文本文件。

对应到数据就是

字符:一律ASCII码

数值型数据:既可以ASCII码,又可以二进制

例:

给一个整数10000(int),以ASCII码存就是占5个字节,但是以二进制形式就是4个字节


7、文件读取结束的判定

feof

注意:在文件读取中,绝不能用feof的返回值来判断文件是否结束,而是应用于文件已经结束了,是读取失败结束的,还是遇到文件结尾结束的。

文件正常结束会返回一个非0的值

ferror

不为-1就是打开失败


 所以到底该怎么判断文件结束?

对于文本文件,判断返回值是否未EOF(end of file)

对于二进制,fread在读取时,返回的是实际读取完整元素的个数,如果发现读取到的完整元素的个数<指定元素的个数,这就是最后一次读取了(但实际上在系统调用read的层面,有很多情况都能导致读到的完整元素个数(ssize_t)<指定元素个数,此处我们不做考虑)。


用上面的方法得知文件结束后我们再用feof函数

例:

假设test.txt文件中有一份代码,要求把test.txt文件拷贝一份,生成test2.txt

test.txt

int main()
{FILE* pfread = fopen("test.txt", "r");if (pfread == NULL){perror("fopen\n");}//写文件FILE* pfwrite = fopen("test2.txt", "w");if (pfwrite == NULL){//这次打开失败了说明第一次打开成功了,所以得释放第一个fclose(pfread);pfread = NULL;return 1;}//从pfread里读,写到pfwrite里int ch = 0;while ((ch = fgetc(pfread)) != EOF){fputc(ch, pfwrite);}//关文件fclose(pfread);pfread = NULL;fclose(pfwrite);pfwrite = NULL;
}

运行之后

test2果然也有了相同的代码

下来该判断文件如何结束的了

if (ferror(pfread))puts("I/O error when reading\n");else if (feof(pfread))puts("EOF reach successfully\n");

(正常结束了)


8、文件缓冲区

先给到大家一张图,然后再举一个例子

先举个现实生活中的例子

  比如你在北京,你的朋友在济南,你想给他寄一个东西,所以你就跑到你们学校的快递站,填好信息。

   此时你的快递就被寄出去了吗?没有,为什么?为什么不马上寄出去?

   如果说你刚走了,快递被一辆车寄出去了,又有一个人来了,填的信息也是寄向济南,然后再派一辆车寄吗?这成本太高了,肯定不能这么做

   所以怎么办? 快递站有一个专门放寄往济南的柜子,柜子满了再寄,也就是要等一波寄往济南的快递,然后只派一辆车寄,这成本就小很多了呀

对应于计算机我们再举一个例子

比如我写数据,我想往硬盘上写,但是这数据不是你能写的,你得告诉操作系统给你写、

操作系统是很忙的,你跟操作系统说:哥们,往磁盘写个数据,操作系统停下手上的活给你写;过一会儿你又说:哥们,往磁盘写个数据……那操作系统什么都不干,刚给你写数据?

那效率太低了。这个时候就要用的缓冲区了

你往磁盘写数据,先往缓冲区上写,缓冲区满了,操作系统再一波往磁盘上写。

所以缓冲区是很有必要的

注意:这波我们学的缓冲区是C语言给我们提供的,也就是说是一个语言层的缓冲区


 总结

 做总结,还是那句话,这篇博客只能带大家对文件有一个浅显的认识,在正式学了操作系统的基础IO和文件系统,才能对这些有更深刻的认识。

水平有限,还请各位大佬指正。如果觉得对你有帮助的话,还请三连关注一波。希望大家都能拿到心仪的offer哦。

每日gitee侠:今天你交gitee了嘛

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

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

相关文章

Java重修第一天—学习数组

1. 认识数组 建议1.5倍速学习&#xff0c;并且关闭弹幕。 数组的定义&#xff1a;数组是一个容器&#xff0c;用来存储一批同种类型的数据。 下述图&#xff1a;是生成数字数组和字符串数组。 为什么有了变量还需要定义数组呢&#xff1f;为了解决在某些场景下&#xff0c;变…

ORACLE Primavera Unifier v23.12 最新虚拟机(VM)分享下载

引言 根据上周的计划&#xff0c;我近日简单制作了一个基于ORACLE Primavera Unifier 最新版23.12的虚拟机演示环境&#xff0c;里面包括了unifier的全套系统服务 此虚拟系统环境仅用于演示、培训和测试目的。如要在生产环境中使用此虚拟机&#xff0c;请您与Oracle 销售代表联…

知虾电商(Shopee):东南亚领先电商平台的十大关键特点**

知虾电商&#xff08;Shopee&#xff09;作为东南亚地区领先的电子商务平台&#xff0c;由Sea Group&#xff08;前称Garena&#xff09;在2015年创立。知虾电商以移动优先的策略迅速崛起&#xff0c;为用户提供了一个便捷、安全的在线购物环境。以下是知虾电商的一些关键特点&…

服务器执行rm命令时自动记录到审计日志中

目的 当在服务器上执行类似于 rm 命令时&#xff0c;自动记录该命令执行的时间&#xff0c;在哪里执行的&#xff0c;删除的什么文件&#xff0c;记录到审计日志中&#xff0c;能够查找到某些文件丢失原因 配置 # 需要root权限&#xff0c;sudo不行&#xff0c;这里假设执行…

RocketMQ5-01云原生和AI演变下的架构重构

2022年9月22日&#xff0c;迎来 RocketMQ5 的发版&#xff0c;距离 2017 发布的 4.X 时代&#xff0c;RocketMQ 迎来 5.X 时代。 RocketMQ 4.X 时代已经使众多开发者和项目受益&#xff0c;但是随着关注度、使用量逐步上升以及云原生时代的到来&#xff0c;也对其自身架构带来…

计算机网络课程设计-企业网三层架构

&#xff08;单人版&#xff09; 摘 要 本篇报告主要解决了为一家名为西宫的公司网络搭建问题&#xff0c;该网络采用企业网三层架构对完了过进行设计。首先使用以太网中继&#xff0c;主要使用VLAN划分的技术来划定不同部门。使用MSTP对每个组配置生成树&#xff0c;防止交换机…

【软件测试】2024年准备中/高级测试岗技术面试...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 1、软件测试基础知…

Unity中URP下统一不同平台下的z值

文章目录 前言一、ComputeFogFactor 来计算雾效混合因子二、UNITY_Z_0_FAR_FROM_CLIPSPACE 来统一计算不同平台下的Z值1、DirectX平台2、GL平台下&#xff08;在Unity.2022.LTS下&#xff0c;该功能没有完善)3、Opengl下 前言 在之前的文章中&#xff0c;我们实现了URP下的雾效…

天津最新web前端培训班 如何提升web技能?

随着互联网的迅猛发展&#xff0c;web前端成为了一个热门的职业方向。越来越多的人希望能够通过学习web前端技术来提升自己的就业竞争力。为了满足市场的需求&#xff0c;许多培训机构纷纷推出了web前端培训课程。 什么是WEB前端 web前端就是web给用户展示的东西&#xff0c;…

python+selenium爬虫笔记

本文只是做例子&#xff0c;具体网站路径麻烦你们换下&#xff0c;还有xpath路径也换下 一、安装所需要的组件&#xff08;此处采用谷歌&#xff09; 1、安装驱动 查看你的浏览器版本&#xff0c;去安装对应的版本 下载驱动 下载驱动路径 之前版本的 输入这个路径下载下来解压…

【Bootstrap5学习 day12】

Bootstrap5 导航 Bootstrap5提供了一种简单快捷的方法来创建基本导航&#xff0c;它提供了非常灵活和优雅的选项卡和Pills等组件。Bootstrap5的所有导航组件&#xff0c;包括选项卡和Pillss&#xff0c;都通过基本的.nav类共享相同的基本标记和样式。 创建基本导航 要创建简单…

亚马逊店铺遇到账号申诉模版分享

1.表达诚意&#xff0c;先认错再说&#xff1a;我知道&#xff0c;最近我们在Amazon.com上作为卖家的表现已经低于亚马逊和我们自己的质量标准。 2.清楚分明的格式&#xff1a;我们库存管理的混乱导致了延迟发货&#xff0c;更糟糕的是&#xff0c;物品无法使用。当延迟发货和…

对话新七天创始人&CEO左英杰:品牌直播电商出圈“五步法”

整理 | 飞族 编辑 | 渔舟 出品&#xff5c;极新&#xff06;北京电子商务协会 AI、AIGC、VR等数智化新技术发展日新月异&#xff0c;在直播电商领域的应用和探索逐渐深入&#xff0c;从内容生成、创意优化、购物体验、智能客服、精准营销等方面提供全方位全链路的赋能&#…

内网穿透的应用-使用Docker本地部署可编辑导航页结合内网穿透实现远程访问

文章目录 1. 使用Docker搜索镜像2. 下载镜像3. 查看镜像4. 启动容器5. 浏览器访问6. 远程访问6.1 内网穿透工具安装6.2 创建远程连接公网地址6.3 使用固定二级子域名地址远程访问 今天和大家分享如何使用Docker本地部署一个开源的简约风格网址导航页&#xff0c;支持五种搜索引…

湖南大学-数据库系统-2023期末考试【原题】

前言 早上11&#xff1a;00考完的考试&#xff0c;下午回来打了三把LOL之后&#xff0c;凭着回忆把题目重现出来了。 在复习的时候刷了15&#xff0c;16&#xff0c;17&#xff0c;18&#xff0c;19&#xff0c;21六年的卷子&#xff0c;感觉题目都差不多&#xff0c;但是难度…

记一次 .NET某股票交易软件 灵异崩溃分析

一&#xff1a;背景 1. 讲故事 在dump分析的旅程中也会碰到一些让我无法解释的灵异现象&#xff0c;追过这个系列的朋友应该知道&#xff0c;上一篇我聊过 宇宙射线 导致的程序崩溃&#xff0c;后来我又发现了一例&#xff0c;而这一例恰恰是高铁的 列控连锁一体化 程序&…

web动态月球特效

文章目录 效果预览文件分布代码 效果预览 文件分布 代码 鼠标点击特效 fireworks.js class Circle {constructor({ origin, speed, color, angle, context }) {this.origin originthis.position { ...this.origin }this.color colorthis.speed speedthis.angle anglethi…

C# OpenCvSharp DNN Gaze Estimation

目录 介绍 效果 模型信息 项目 代码 frmMain.cs GazeEstimation.cs 下载 C# OpenCvSharp DNN Gaze Estimation 介绍 训练源码地址&#xff1a;https://github.com/deepinsight/insightface/tree/master/reconstruction/gaze 效果 模型信息 Inputs ----------------…

【RabbitMQ】1 消息中间件MQ概述

目录 什么是消息中间件为什么使用消息中间件流量削峰应用解耦异步处理 主流消息中间件及选型选取原则RabbitMQRocketMQKafka如何选择 消息中间件应用场景电商秒杀案例拉勾B端C端数据同步案例支付宝购买电影票 什么是消息中间件 维基百科对消息中间件的解释&#xff1a;面向消息…

pandas保存style到excel文件中

更多pandas style用法请参考&#xff1a;https://pandas.liuzaoqi.com/doc/chapter8/style.html 示例程序 import numpy as np import pandas as pd# 示例数据 dataframe pd.DataFrame({"date": pd.date_range("2024-01-01", "2024-02-01"),&…