文件操作详解(万字长文)

C语言文件操作

  • 一、为什么使用文件?
  • 二、文件分类
  • 三、文件的打开和关闭
  • 四、文件的顺序读写
    • 4.1fputc
    • 4.2fgetc
    • 4.3fputs
    • 4.4fgets
    • 4.5 fprintf
    • 4.6 fscanf
    • 4.7 fwrite
    • 4.8 fread
  • 五、文件的随机读写
    • 5.1 fseek
    • 5.2 ftell和rewind
    • 六、文件读取结束的判定
    • 七、文件缓冲区

一、为什么使用文件?

我们以创建变量举例,假设我们创建一个整型变量b,并且我们将它初始化为100,这样我们写的数据是储存在电脑的内存中的,然后我们退出程序,内存回收,数据就丢失了,等到再次运行程序的时候是看不到上一次程序的数据的。那我们能不能把它长久保存下来呢?这就需要用到文件,文件是保存在磁盘上的,使用磁盘(文件)来储存数据我们就可以对数据进行持久化储存。

二、文件分类

  • 程序文件:包括源程序文件(后缀为.c)目标文件(在windows环境下后缀为.obj)可执行程序(在windows环境下后缀为.exe)。
  • 数据文件:文件也不一定都是程序,也有可能文件中存放的是程序运行时读写的数据,这就是数据文件。

文件名:一个文件要有一个唯一的文件标识,以便用户识别和引用。
文件名包含三个部分:文件路径 + 文件名主干 + 文件后缀
例如:c:\code\test.c 中的c:\code\就是文件路径,test就是文件名主干,.c就是文件后缀。

二进制文件和文本文件
根据数据的组织形式,数据被称为二进制文件文本文件。
数据在内存中是以二进制的形式存储的,如果它不加转换的输出到外存的文件中,就是二进制文件,如果要求在外存的基础上以ASCll码的形式存储,这时候就需要在储存前转换,以ASCll码形式储存的文件就是文本文件

三、文件的打开和关闭

文件在读之前需要先打开文件,这时候你就需要一枚钥匙(fopen),在使用之后你还要关闭文件,这时候你需要一把锁(fclose)。

这两个函数都在#include <stdio.h>下,接下来我们来讲解这两个函数。
首先来看fopen的函数原型:

FILE* fopen(const char* filename,const char*mode);
//filename就是你要打开的文件名
//mode是你要以什么方式打开,像读、写等等

打开完成后fopen会返回一个FILE*类型的指针用于文件操作,如果打开失败fopen会返回空指针(NULL),所以通常我们需要对fopen的返回值进行判断。
关于文件的使用方式可以参照以下表格:

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

等等还有很多种操作,这里小编只列举了这几种方式来进行解释。
之后是fclose的函数原型

int fclose(FILE* stream);
//stream是指向文件的FILE*类型的指针

示例
首先我不创建text.c的文件:

#include<stdio.h>int main()
{FILE* pf;pf = fopen("text.c", "r");if (pf == NULL){printf("打开失败");}else{printf("打开成功");}fclose(pf);pf = NULL;return 0;
}

结果:
在这里插入图片描述
之后我再创建文件:
在这里插入图片描述
结果:
在这里插入图片描述

四、文件的顺序读写

既然我们已经可以打开关闭文件了,那总要做点什么吧,比如说往文件里面写一些数据,或者读一些数据,这时候就需要用到我们的函数,首先介绍顺序读写,之后介绍随机读写。

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

4.1fputc

函数原型:
在这里插入图片描述
这个函数的作用是向stream指向的文件中写东西。
注意:fputc是向文件中写数据,文件打开方式应该使用"w"
示例:

#include<stdio.h>int main()
{FILE* pf;pf = fopen("text.txt", "w");if (pf == NULL){perror("fopen");return 1;}//写文件for (int i = 'a';i < 'z';i++){fputc(i, pf);}fclose(pf);pf = NULL;return 0;
}

程序执行前:
在这里插入图片描述
程序执行后:
在这里插入图片描述

4.2fgetc

函数原型:
在这里插入图片描述
fgetc函数的作用是从文件中读取数据,我们可以把读取到的数据打印在屏幕上。

注意:此时是从文件中读取数据是只读的情况,所以文件打开方式应该选用“r”,当文件中的字符被逐个读完之后没有字符可读,或者一开始就没有字符可读时,fgetc函数会返回EOF(-1),所以我们可以以EOF来判断是否读取结束。

示例

#include<stdio.h>int main()
{FILE* pf;pf = fopen("text.txt", "r");if (pf == NULL){perror("fopen");return 1;}//读文件int c = 0;while ((c = fgetc(pf)) != EOF){printf("%c ", c);}fclose(pf);pf = NULL;return 0;
}

结果:
在这里插入图片描述

4.3fputs

函数原型:
在这里插入图片描述
注意:向文件中写入字符串,打开文件方式用“w”

实例:

#include<stdio.h>int main()
{FILE* pf;pf = fopen("text.txt", "w");if (pf == NULL){perror("fopen");return 1;}//写文件fputs("hello world\n", pf);fputs("hello new world\n",pf);fclose(pf);pf = NULL;return 0;
}

结果:
在这里插入图片描述

4.4fgets

函数原型:
在这里插入图片描述
示例:

#include<stdio.h>int main()
{FILE* pf;pf = fopen("text.txt", "r");if (pf == NULL){perror("fopen");return 1;}//读文件char c[101];char s[101];fgets(c, 13, pf);fgets(s, 16, pf);printf("%s", c);printf("%s", s);fclose(pf);pf = NULL;return 0;
}

结果:
在这里插入图片描述

使用fgets的注意事项:
1、当你要求它读取8个字符的时候他其实会从文件中读取7个字符剩下的那个字符空间他会用来储存‘\0’。
2、不知道大家有没有发现我的打印函数里面都没有添加换行符,但打印出来却换行了,这是因为fgets读取到了文件行末尾的换行符。

4.5 fprintf

函数原型:
在这里插入图片描述
首先函数的第一个参数是指向文件的FILE*指针,第二个参数是传入数据的形式,像%d、%f这些。
示例:

#include<stdio.h>int main()
{FILE* pf;pf = fopen("text.txt", "w");if (pf == NULL){perror("fopen");return 1;}//写文件fprintf(pf, "%d %lf %c", 100, 3.14, 'a');fclose(pf);pf = NULL;return 0;
}

结果:
在这里插入图片描述

4.6 fscanf

函数原型:
在这里插入图片描述
示例:

#include<stdio.h>int main()
{FILE* pf;pf = fopen("text.txt", "r");if (pf == NULL){perror("fopen");return 1;}int n;double d;char c;//读文件fscanf(pf, "%d %lf %c", &n,&d,&c);printf("%d\n", n);printf("%f\n", d);printf("%c\n", c);fclose(pf);pf = NULL;return 0;
}

结果:
在这里插入图片描述

4.7 fwrite

函数原型:
在这里插入图片描述

其中ptr指针指向的是要传文件数据的数组,size是一次传送的字节大小,count是传送的次数,stream是FILE*类型的指针。此时文件的打开方式应该是“wb”。

示例:

#include<stdio.h>int main()
{FILE* pf;pf = fopen("text.txt", "wb");if (pf == NULL){perror("fopen");return 1;}//写文件int a[] = { 1,2,3 };fwrite(a,sizeof(a[0]),3,pf);fclose(pf);pf = NULL;return 0;
}

结果:
在这里插入图片描述
当我们以二进制的形式存入数据的时候,它给出的结果我们已经识别不出来了,我们转化为2进制再看一下:
在这里插入图片描述
以二进制的方式打开我们发现的确储存了1,2,3,而且是以16进制的形式储存的和内存的储存形式相同。

4.8 fread

函数原型:
在这里插入图片描述

其中ptr指针指向的是要存放数据的数组,size是从文件读取的字节大小,count是读取的个数,stream是FILE*类型的指针。此时文件的打开方式应该是“rb”。

示例:

#include<stdio.h>int main()
{FILE* pf;pf = fopen("text.txt", "rb");if (pf == NULL){perror("fopen");return 1;}//读文件int arr[4] = { 0 };for (int i = 0;i < 3;i++){fread(arr + i, sizeof(arr[0]), 1, pf);printf("%d ", arr[i]);}fclose(pf);pf = NULL;return 0;
}

结果:
在这里插入图片描述

五、文件的随机读写

5.1 fseek

函数原型:
在这里插入图片描述
第一个参数是一个FILE*类型的指针,第二个参数是偏移量,第三个参数是参照系。那这个具体是什么意思呢?就是选择一个参照系,比如我选择文件开头,然后偏移量选择3,那就是从文件中第三个字符开始读取的意思。

关于参照系这里有一个表格,它一共有三个取值:
在这里插入图片描述
SEEK_SET:文件的开始位置
SEEK_CUR:光标的当前位置
SEEK_END:文件末尾位置

示例:

#include<stdio.h>int main()
{FILE* pf;pf = fopen("text.txt", "r");if (pf == NULL){perror("fopen");return 1;}//读文件char arr[10];fseek(pf, -11, SEEK_END);arr[0] = fgetc(pf);fputc(arr[0], stdout);fclose(pf);pf = NULL;return 0;
}

结果:
在这里插入图片描述
另外两个origin取值也是相同的用法。

5.2 ftell和rewind

ftell的函数原型:
在这里插入图片描述
它只有一个参数就是文件指针,它的作用是返回光标当前位置。

rewind的函数原型:
在这里插入图片描述
它也只有一个参数就是文件指针,它的作用是让光标回到文件的起始位置。

示例:

#include<stdio.h>int main()
{FILE* pf;pf = fopen("text.txt", "r");if (pf == NULL){perror("fopen");return 1;}//读文件char arr[10];fseek(pf, -11, SEEK_END);arr[0] = fgetc(pf);fputc(arr[0], stdout);long int n = ftell(pf);printf("\n%ld\n", n);rewind(pf);n=ftell(pf);printf("%ld", n);fclose(pf);pf = NULL;return 0;
}

结果:
在这里插入图片描述

六、文件读取结束的判定

C语言中有一个函数是feof,它的作用是当文件读取结束的时候,判断读取的原因是不是遇到文件尾而结束。
注意:在文件读取的过程中不能用feof函数的返回值直接判断文件是否结束。
它的函数原型:
在这里插入图片描述
那如何判断文件是否读取结束呢?
对于文本文件
例如:fgetc判断返回值是不是EOF,fgets判断返回值是不是NULL。
对于二进制文件
二进制文件是否读取结束,是判断返回值是不是小于实际要读的个数。
例如:fread判断返回值是否小于实际要读的个数。

示例:

#include<stdio.h>int main()
{FILE* pf;pf = fopen("text.txt", "r");if (pf == NULL){perror("fopen");return 1;}//读文件int c;while ((c = fgetc(pf)) != EOF){putchar(c);}if (ferror(pf))//判断是不是异常结束{printf("\nI/O error when reading");}else if (feof(pf))//判断是不是正常结束{printf("\nEnd of file reached successfully");}fclose(pf);pf = NULL;return 0;
}

结果:
在这里插入图片描述

七、文件缓冲区

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

例如:
当我们输入数据时,系统会开辟一个输入缓冲区,假设这个缓冲区的大小是固定的,我们输入数据时它会等到缓冲区被充满后在一起送到磁盘上,输出缓冲区也是这样。这样就大大解放了程序的空间和时间,使计算机能够同时处理更多的事。
在这里插入图片描述

总结
以上就是全部的今天博客内容,内容稍微有点多,读者朋友可以点个关注,博主后续还会给大家带来更多的优质内容~
另外,如果有什么问题,可以在评论区留言,博主看到后,会一一回复。
好了,让我们下期博客再见!
(~ ̄▽ ̄)~

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

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

相关文章

基于 JDBC 的后端与 MySQL 数据库交互 javaweb

一、了解JDBC 二、添加MySQL的JDBC驱动包 三、使用JDBC连接数据库应用&#x1f517; 3.1创建一个包 3.2 查找实例 3.3 修改添加删除实例 四、封装 &#x1f4e6; DBConnection.java MysqlUtil.java 测试使用一下 测试1 测试2 在后端开发中&#xff0c;与数据库进行交…

贪心算法--

1.柠檬水找零 link:860. 柠檬水找零 - 力扣&#xff08;LeetCode&#xff09; code class Solution { public:bool lemonadeChange(vector<int>& bills) {// 贪心算法&#xff0c; 优先花出大面额bill&#xff0c; 尽可能保护小面额billint five 0, ten 0;// 不…

基于YOLO11深度学习的电瓶车进电梯检测与语音提示系统【python源码+Pyqt5界面+数据集+训练代码】

《------往期经典推荐------》 一、AI应用软件开发实战专栏【链接】 项目名称项目名称1.【人脸识别与管理系统开发】2.【车牌识别与自动收费管理系统开发】3.【手势识别系统开发】4.【人脸面部活体检测系统开发】5.【图片风格快速迁移软件开发】6.【人脸表表情识别系统】7.【…

github生成badges的方法

在Github页面上生成类似下面这样的badge的方法 你可以通过以下步骤在GitHub个人主页的README中创建类似的技术栈徽章&#xff1a; 一、使用 Shields.io 生成徽章 Shields.io 是一个开源徽章生成工具&#xff0c;支持自定义文本、颜色、图标等参数。 1. 基础模板 https://…

vue3 二次封装uni-ui中的组件,并且组件中有 v-model 的解决方法

在使用uniappvue3开发中&#xff0c; 使用了uni-ui的组件&#xff0c;但是我们也需要自定义组件&#xff0c;比如我要自定一个picker 的组件&#xff0c; 是在 uni-data-picker 组件的基础上进行封装的 父组件中的代码 <classesselect :selectclass"selectclass"…

Spring Boot启动流程及源码实现深度解析

Spring Boot启动流程及源码实现深度解析 一、启动流程概述 Spring Boot的启动流程围绕SpringApplication类展开&#xff0c;核心流程可分为以下几个阶段&#xff1a; 初始化阶段&#xff1a;推断应用类型&#xff0c;加载ApplicationContextInitializer和ApplicationListene…

爬虫案例七Python协程爬取视频

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、Python协程爬取视频 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 爬虫案例七协程爬取视频 提示&#xff1a;以下是本篇文章正文…

uni-app开发的App和H5嵌套封装的App,以及原生App有什么区别

uni-app 开发的 App 和 H5 嵌套封装的 App 是两种不同的开发模式&#xff0c;虽然它们都可以实现跨平台开发&#xff0c;但在技术实现、性能、功能支持等方面有显著区别。以下是详细对比&#xff1a; 1. uni-app 开发的 App uni-app 是一个基于 Vue.js 的跨平台开发框架&#…

Python 爬虫实战案例 - 获取拉勾网招聘职位信息

引言 拉勾网&#xff0c;作为互联网招聘领域的佼佼者&#xff0c;汇聚了海量且多样的职位招聘信息。这些信息涵盖了从新兴科技领域到传统行业转型所需的各类岗位&#xff0c;无论是初出茅庐的应届生&#xff0c;还是经验丰富的职场老手&#xff0c;都能在其中探寻到机遇。 对…

LM Studio 替换源的方式解决huggingface.co无法访问的问题

安装软件完成之后&#xff0c;不要打开&#xff0c;打开了就直接关闭 在安装目录下&#xff0c;比如我安装在E:\Program Files\LM Studio 下面三个文件中的huggingface.co全部替换为hf-mirror.com然后再打开即可。 E:\Program Files\LM Studio\resources\app\.webpack\rende…

【模拟CMOS集成电路设计】带隙基准(Bandgap)设计与仿真(基于运放的电流模BGR)

【模拟CMOS集成电路设计】带隙基准&#xff08;Bandgap&#xff09;设计与仿真 前言工程文件&部分参数计算过程&#xff0c;私聊~ 一、 设计指标指标分析&#xff1a; 二、 电路分析三、 仿真3.1仿真电路图3.2仿真结果(1)运放增益(2)基准温度系数仿真(3)瞬态启动仿真(4)静态…

微服务拆分-远程调用

我们在查询购物车列表的时候&#xff0c;它有一个需求&#xff0c;就是不仅仅要查出购物车当中的这些商品信息&#xff0c;同时还要去查到购物车当中这些商品的最新的价格和状态信息&#xff0c;跟购物车当中的快照进行一个对比&#xff0c;从而去提醒用户。 现在我们已经做了服…

机动车授权签字人考试的报名条件是什么?

机动车授权签字人考试的报名条件通常如下&#xff1a; 学历职称与工作经验要求 中级职称及以上&#xff1a;应具备中级及以上专业技术职称&#xff0c;且从事相关检验检测工作三年及以上。如果承检车型有专项作业车、大型客车、校车和危险货物运输车等&#xff0c;若不是相关专…

智慧工厂监测信息系统:构筑安全的数字化未来

在现代工业的浪潮中&#xff0c;智慧工厂已成为推动生产效率和产品质量提升的关键力量。为了确保这一先进生产模式的稳健运行&#xff0c;智慧工厂监测信息系统应运而生&#xff0c;并通过一系列安全措施&#xff0c;为企业的数字化转型保驾护航。 安全注册&#xff0c;筑牢第…

P2P中NAT穿越方案(UDP/TCP)(转)

转自&#xff1a;P2P中NAT穿越方案&#xff08;UDP/TCP&#xff09;_udp反向链接-CSDN博客 同&#xff1a;P2P中NAT穿越方案&#xff08;UDP/TCP&#xff09; - 知乎 (zhihu.com) 本文介绍了传统基于udp的打洞方式&#xff0c;更进一步阐述了tcp打洞的原理&#xff0c;是对于…

算法 之 树形dp 树的中心、重心

文章目录 重心实践题目小红的陡峭值 在树的算法中&#xff0c;求解树的中心和重心是一类十分重要的算法 求解树的重心 树的重心的定义&#xff1a;重心是树中的一个节点&#xff0c;如果将这个点删除后&#xff0c;剩余各个连通块中点数的最大值最小&#xff0c;那么这个节点…

游戏引擎学习第146天

音高变化使得对齐读取变得不可能&#xff0c;我们可以支持循环声音了。 我们今天的目标是完成之前一段时间所做的音频代码。这个项目并不依赖任何引擎或库&#xff0c;而是一个教育项目&#xff0c;目的是展示从头到尾运行一个游戏所需要的全部代码。无论你对什么方面感兴趣&a…

深入理解MySQL主从原理

导读 高鹏&#xff08;网名八怪&#xff09;&#xff0c;《深入理解MySQL主从原理》系列文的作者。 本系列通过GTID、Event、主库、从库、案例分析&#xff0c;五大块来详细讲解主从原理。 这篇文章重在学习笔记整理&#xff01; 在学习《深入理解MySQL主从原理》一书时&…

前端数据模拟利器 Mock.js 深度解析

前端数据模拟利器 Mock.js 深度解析 一、Mock.js 核心价值 1.1 为何需要数据模拟 前后端并行开发加速接口文档驱动开发异常场景模拟测试演示环境数据构造 1.2 Mock.js 核心能力 // 典型数据生成示例 Mock.mock(/api/user, {"users|5-10": [{"id|1": 1…

Phi-4-multimodal:图、文、音频统一的多模态大模型架构、训练方法、数据细节

Phi-4-Multimodal 是一种参数高效的多模态模型&#xff0c;通过 LoRA 适配器和模式特定路由器实现文本、视觉和语音/音频的无缝集成。训练过程包括多阶段优化&#xff0c;确保在不同模式和任务上的性能&#xff0c;数据来源多样&#xff0c;覆盖高质量网络和合成数据。它的设计…