C语言的文件操作(炒详解)
⭐回顾回顾文件操作的相关细节⭐
欢迎大家指正错误
📝在之前的学习中,不管增加数据,减少数据,当程序退出时,所有的数据都会销毁,等下次运行程序时,又要重新输入相关数据,如果一直像这样不能保持相关程序的数据会非常难受,我们想要把数据记录下来,只有我们们想删除数据的时候数据才会销毁,这就涉及了数据持久化,利用文件操作函数,我们可以将数据放在文件之中,下次需要使用可以直接访问
🔥我们一般的数据持久化的方式就是把数据放在磁盘文件中,使用文件我们可以将数据直接存放到电脑的硬盘上,以做到数据的持久化。
目录
文件的基本操作
文件指针
文件的打开和关闭
利用"w"介绍相对路径
文件的读写
fputc函数
fgetc函数
fputs函数
fgets函数
fprintf函数和fscanf函数
sprintf和sscanf函数
二进制的读写函数
文件的定位
fseek函数
rewind函数
ftell函数
📜介绍一下文件名
一个文件要有一个唯一的文件标识,以便用户识别和使用。
文件名包括三部分:
文件路径+文件名主干+文件后缀
例如:C:\code\test.txt
文件的路径的讲解
我们传过去的路径有两种
①绝对路径
例如 "D:\桌面\planegames_boxed.exe"
"C:\Users\Public\Videos"
👉在这里要注意哦,如果这样直接传地址会有转义字符的影响的。
在传参时,尽量在每个斜杠前加一个斜杠,就可以解决转义字符可能带来的影响
②相对路径
💭下边将会利用文件读写时的操作进行介绍更易理解
文件的基本操作
👉文件的基本操作包括文件的打开与关闭,除了标准的输入输出文件外,其他所有的文件都必需先打开再使用,使用后还必须关闭该文件。
文件指针
📌文件指针是一个指向文件有关信息的指针,这些信息通常包括文件名,状态和当前的位置,他们保存在一个结构体变量中,在使用文件时需要在内存中为其分配空间,用来存放文件的基本信息,该结构体类型是系统定义的,C语言规定该类型为FILE。
不同的C编译站的FILE类型包括的内容完全不同,但是大同小异,这里的细节我们不必关心。
一般都是通过创建一个FILE的指针来维护这个FILE结构的变量,这样使用起来可以更加方便。
创建一个FILE*类型的指针变量:
FILE * pf;
pf是一个指向FILE类型数据的指针变量。可以使pf指向某个文件的文件信息区(是一个结构体变量)。通过该文件信息区中的信息就能够访问该文件,就是说通过文件指针变量就能够找到与他关联的文件。
文件的打开和关闭
文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。
(在程序结束前应该关闭所有的文件,目的是为了防止应为没有关闭文件而造成的数据流失。)
ANSIC规定用fopen函数来打开文件,fclose来关闭文件。
打开文件
🏅FILE * fopen(const char* filename(文件名),const char *mode(打开方式));
关闭文件
🏅int fclose (FILE*stream);
打开方式如下
👉用只读方式打开
通过上图来看,如果文件夹中没有该文件,就会返回一个空指针,用perror判断运行后如图,当然,如果创建了data.txt文件,就不会报错啦。
用写方式呢举一个梨子
int main()
{FILE* pfile;pfile = fopen("example","w");if (pfile == NULL){perror("fopen");return 1;}if (pfile != NULL){fputs("fopen example", pfile);fclose(pfile);}return 0;
}
上面的表格我们注意到,用写的方式打开,如果没有文件会生成一个文件,执行相关指令。如果要打开的文件时绝对路径(例如桌面),没有该文件的话也还是会在桌面创建一个出来使用的。
“fputs后续我们会讲,是将字符串输入进文件中去。”
📜运行结果如图
一定要记得关闭程序前关闭所有的文件。
利用"w"介绍相对路径
📝前边加上一个点是当前目录,可以省略。
省略时:
📝删除创建好的lalala,不省略时再次运行
📝我们如果想在上一级目录里面创建lalala呢?
📝在前边加上(.),到达上一级,在上一级的x64里创建lalala
⭐如果还想往前跑,就继续加(.),在文件夹内找到要放置进去的文件夹,这就是文件的相对路径,利用.和\来找到具体的位置,相比较没有绝对路径那么精确。
文件的读写
打开文件后,就可以进行文件的读写,C语言提供了丰富的文件操作函数,现在对其诸个介绍。以下所有函数默认FILE * fp。
fputc函数
ch = fputc (ch,fp);
该函数的作用是把一个字符写进磁盘文件fp中,其中ch就是要输入的数据。fp是文件指针变量,如果函数输出成功,返回的就是输出的字符,如果输出失败,就返回EOF。
⭐看个例子
int main()
{FILE* fp;char ch;if ((fp = fopen("file", "w")) == NULL){assert("fopen");}ch = getchar();while (ch != '#'){fputc(ch, fp);ch = getchar();}fclose(fp);return 0;
}
⭐运行后如图:
📑这个例子读取到#则停止。
fgetc函数
ch = fgetc (fp);
这个函数的作用是从指定文件(fp指向的文件)读取一个字符赋予ch。需要注意的是,文件必须是读或者读写的方式打开。
💡上面我们将file文件里写进了几个字符,现在我们来取出他们
int main()
{FILE* fp;char ch;fp = fopen("file", "r");ch = fgetc(fp);while (ch != EOF){putchar(ch);ch = fgetc(fp);}fclose(fp);return 0;
}
💡运行后如图,可以发现确实将文件中写入的字符全部拿到了。
fputs函数
fputs(字符串,文件指针);
和fputc不同的是,这个函数的作用是向指定文件中写入一个字符串,其中字符串可以是字符常量,也可以是字符数组名,指针或者变量。
💭看例子
int main()
{FILE* fp;char filename[30], str[30];printf("输入文件名\n");scanf("%s", filename);if ((fp = fopen(filename, "w")) == NULL){perror("fopen");}printf("输入字符串\n");getchar();gets(str);fputs(str, fp);fclose(fp);return 0;
}
💡运行后如图
fgets函数
fgets(字符数组名,n,文件指针)
该函数的作用是从指定文件中读一个字符串到字符数组中,n表示所得到的字符串中字符的个数(包含字符"\0")
要知道在上边我们在filecom里写进了hello world!
int main()
{FILE* fp;char str[30];if ((fp = fopen("filecom", "r")) == NULL){perror("fopen error");}fgets(str, 11, fp);printf("%s", str);return 0;
}
💭运行后如图
上面所说包含"\0",在这里我们打印11个字符,然而这里直有10个字符(包含空格),这是因为"\0"也占了一个字符位。
fprintf函数和fscanf函数
我们对printf函数和scanf应该都已经很熟悉了,下面要讲解的fprint和fscnaf与他们的作用相似,他们最大的区别就是读写的对象不同,fprintf和fscanf函数读写的对象不是终端,而是磁盘文件。
我们在cplusplus官网比较一番
相比较printf函数,fprintf多了一个参数,fprintf函数形式如下
fprintf(fp,"%d",i);
作用是将整型变量i的值以"%d"的格式输出到fp指向的文件中
💭举个梨子
int main()
{FILE* fp;int i = 666;if ((fp = fopen("filenum", "w")) == NULL){perror("fopen error");}fprintf(fp, "%d", i);return 0;
}
创建一个filenum文件,写入666;
运行结果如下:
⭐如果是%c写入呢,就要参考参照ASCII码表
fscanf函数
格式如下
fscanf(文件类型指针,格式字符串,输入列表);
fscanf(fp , "%d" , &i);
⭐我们先写入abcdefg
💡然后以字符的形式输出
运行后结果正常,输出为参照ASCII对应的数字。
sprintf和sscanf函数
前边已经了解了fprintf和fscanf函数
💡再对比前边的fprintf函数,相比于fprintf函数将内容写进文件中,可以发现sprintf函数的第一个参数变成了一个字符指针,sprintf的作用即是将格式化的数据转化成字符串,放在传进来的字符数组里。
举一个例子
typedef struct Nums
{int a;char b;double c;
}Nums;int main()
{char str[30] = "0";Nums nums = { 3,'f',1.5 };sprintf(str, "%d %c %lf\n", nums.a, nums.b, nums.c);printf("%s", str);return 0;
}
仔细观擦发现和printf函数差不多,作用也很相似。
sscanf同理
💡sscanf从字符串中读取格式化的数据。
typedef struct Nums
{int a;char b;double c;
}Nums;int main()
{char str[30] = "0";Nums nums = { 3,'f',1.5 };Nums nums1 = { 0 };sprintf(str, "%d %c %lf\n", nums.a, nums.b, nums.c);//printf("%s", str);sscanf(str, "%d %c %lf", &(nums1.a), &(nums1.b), &(nums1.c));printf("%d %c %lf", nums.a, nums.b, nums.c);return 0;
}
📖读取str内的元素放进nums1中去,此时再打印结构体变量nums1就会发现已经把str内的数据搬进nums1中啦。
二进制的读写函数
⭐前边所介绍的fputc和fgetc函数,每次只能读写文件的一个字符,但我们在编写程序的过程中常常需要对整块数据进行读写,例如,对一个结构体类型的变量值进行读写,下面进行fread和fwrite函数。
因为写进去的是二进制文件,所以当我们用记事本打开时,看到的都是乱码。
代码如下
typedef struct Nums
{int a;char b;double c;char str[10];
}Nums;
int main()
{Nums nums = { 1,'c',1.5,"heihei"};FILE* pf = fopen("data.txt", "wb");if (pf == NULL){perror("fopen");return 1;}fwrite(&nums, sizeof(Nums), 1, pf);fclose(pf);return 0;
}
运行后如下
👑接下来我们要将它使用fread再读出来,放进一个结构体中,再将其打印出来,将上边的代码改造一下
📜代码如下
typedef struct Nums
{int a;char b;double c;char str[10];
}Nums;
int main()
{Nums nums = { 0 };FILE* pf = fopen("data.txt", "rb");if (pf == NULL){perror("fopen");return 1;}fread(&nums, sizeof(Nums), 1, pf);printf("%d %c %f %s\n", nums.a, nums.b, nums.c, nums.str);fclose(pf);return 0;
}
👉运行后代码如下,我们将nums已经置空了,但打印结果已经说明了一切。
文件的定位
⭐学习了前边的函数,我们这时候又要思考了,在对文件进行操作时,一定要从头开始吗?多不方便哇,这时候就需要文件定位函数来实现对文件的随机读取。
fseek函数
fseek(文件类型指针,位移量,起始点);
这个函数的作用是移动文件内部的位置指针,其中,“文件类型指针”指向被移动的文件;“移动量”表示移动的字节数,要求位移量是long类型数据。“起始点”表示从何处开始计算位移量,规定的起始点有文件首,当前位置,文件末。
表示方法如图
🙉怎么用呢?
fseek(fp,-20,1);
fseek(fp,-20,SEEK_CUR);
代码表示将位置指针从当前位置向后退20个字节。
🙉看代码
int main()
{FILE* file = fopen("data.txt", "w");fputs("This is an apple.", file);fseek(file, 9, 0);fputs(" sam", file);fclose(file);return 0;
}
⭐运行后如图
结合运行结果很容易发现,在替换时将空格也替换了,输入的位移量是九,在输入是从第十个位置继续输入,然后puts里的字符串覆盖原字符串。
fseek(fp,5,0);
💡 此代码的含义是将文件指针指向距离文件首5个字节的位置,也就是指向字符串中的第六个字符。
rewind函数
💭前边讲过了fseek函数,这里介绍的rewind函数也可以起到定位文件指针的作用
int rewind(文件类型指针);
该函数的作用是使位置指针重新返回文件的开头,该函数没有返回值。
举一个例子
int main()
{FILE* fp;char ch;fp = fopen("data.txt", "r");ch = fgetc(fp);while (ch != EOF){putchar(ch);ch = fgetc(fp);}rewind(fp);ch = fgetc(fp);while (ch != EOF){putchar(ch);ch = fgetc(fp);}fclose(fp);return 0;
}
运行结果如图所示
有点懵?再来看一个例子
int main()
{int n;FILE* pfile;char buffer[27];pfile = fopen("myfile.txt", "w+");for (n = 'A'; n <= 'Z'; n++){fputc(n, pfile);}//rewind(pfile);fread(buffer, 1, 26, pfile);fclose(pfile);buffer[26] = '\0';puts(buffer);return 0;
}
可以看到将rewind注释掉后,运行结果如下,这是因为在使用fputc时将文件指针移动到了最后,再读的话就是从最后的位置开始读,所以输出结果为空。
如果将rewind解注释,再次运行
与上次运行的结果不同,此时将文件指针重新返回文件的开头,该函数没有返回值。
ftell函数
嘿嘿嘿,如果上边解释rewind大家还有点不懂,可以结合ftell函数来解释哦!
ftell函数一般形式如下
long ftell(文件类型指针)
该函数的作用是返回文件指针相对于起始位置的偏移量。
⭐利用同样的实例,来看一下是否rewind函数真的把文件指针搞到了最前边。同样也可以摸清ftell函数的作用。
int main()
{int n;int size = 0;FILE* pfile;char buffer[27];pfile = fopen("myfile.txt", "w+");for (n = 'A'; n <= 'Z'; n++){fputc(n, pfile);}size = ftell(pfile);//看一下此时的文件指针的位置printf("%d\n", size);rewind(pfile);//指针退回到开头位置size = ftell(pfile);printf("%d\n", size);//再看一次fread(buffer, 1, 26, pfile);fclose(pfile);buffer[26] = '\0';puts(buffer);return 0;
}
运行后如图
我想已经很明显啦,到了这里文件操作相关的知识点就梳理完毕啦,如果有错误欢迎大家指出!
相关文章:

C语言的文件操作(炒详解)
⭐回顾回顾文件操作的相关细节⭐ 欢迎大家指正错误 📝在之前的学习中,不管增加数据,减少数据,当程序退出时,所有的数据都会销毁,等下次运行程序时,又要重新输入相关数据,如果一直像这…...

27.基于ADS的不等分威尔金森功分器设计
27.基于ADS的不等分威尔金森功分器设计 等分的威尔金森功分器可以使用ADS非常快速的设计出来,但是不等分的功分器却没有便捷的设计方法,在此给出快速的设计方法与案例,方便大家实际设计。 等分版本的威尔金森功分器设计教程:12、…...
Linux自用命令
sudo su/sudo -i:获取root权限 cd:目录切换 cd / 切换到根目录 cd … 切换到上一级目录 cd ~ 切换到home目录 cd - 切换到上次访问的目录 ls:目录查看 ls 查看当前目录下的所有目录和文件 ls -a 查看当前目录下的所有目录和文件(…...

clickhouse union all之后数据量不一致
环境: clickhouse版本:22.8.16.32 问题:clickhouse使用union all查询结果与每一段sql查询结果只和不一致 原因:因为clickhouse版本问题,官方给出不同的解释 解决方案:将union all的每一段sql用括号括起来…...

力扣刷题19-删除链表的倒数第N个节点
题目来源 题目描述: class Solution {public ListNode removeNthFromEnd(ListNode head, int n) {//为了删除的格式一样,引入虚拟头节点ListNode dummyNodenew ListNode(1);dummyNode.nexthead;ListNode slowdummyNode;ListNode fastdummyNode;for(int…...
Unity中的简单数据存储办法
这段代码演示了Unity中的简单数据存储办法 当涉及到不同类型的存储时,下面是一些示例代码来演示在Unity中如何使用不同的存储方法: 1. 临时存储示例代码(内存变量): csharp // 定义一个静态变量来存储临时计分 pub…...

Pytorch-MLP-CIFAR10
文章目录 model.pymain.py参数设置注意事项运行图 model.py import torch.nn as nn import torch.nn.functional as F import torch.nn.init as initclass MLP_cls(nn.Module):def __init__(self,in_dim3*32*32):super(MLP_cls,self).__init__()self.lin1 nn.Linear(in_dim,1…...
SQL2 查询多列
描述 题目:现在运营同学想要用户的设备id对应的性别、年龄和学校的数据,请你取出相应数据 示例:user_profile iddevice_idgenderageuniversityprovince12138male21北京大学Beijing23214male复旦大学Shanghai36543female20北京大学Beijing42…...
算法分享三个方面学习方法(做题经验,代码编写经验,比赛经验)
目录 0 . 前言:(遇到OI不要慌)(只要道路对了,就不怕遥远) 1. 做题经验谈 1.1 做题的目的 1.2 我对于算法比赛的题目的看法 1.2.1 类似题 1.2.2 套模型: 1.3 在训练过程中如何做题 1.4 一些建议&…...

爬虫 — 验证码反爬
目录 一、超级鹰二、图片验证模拟登录1、页面分析1.1、模拟用户正常登录流程1.2、识别图片里面的文字 2、代码实现 三、滑块模拟登录1、页面分析2、代码实现(通过对比像素获取缺口位置) 四、openCV1、简介2、代码3、案例 五、selenium 反爬六、百度智能云…...

视频图像处理算法opencv模块硬件设计图像颜色识别模块
1、Opencv简介 OpenCV是一个基于Apache2.0许可(开源)发行的跨平台计算机视觉和机器学习软件库,可以运行在Linux、Windows、Android和Mac OS操作系统上 它轻量级而且高效——由一系列 C 函数和少量 C 类构成,同时提供了Python、Rub…...
目标检测网络之Fast-RCNN
文章目录 Fast RCNN解决的问题Fast RCNN网络结构RoI pooling layer合并损失函数及其传播统一的损失函数损失函数的反向传播过程Fast RCNN的训练方法样本选择方法SGD参数设置多尺度图像训练SVD压缩全连接层对比实验对比实验使用到的网络结构VOC2010和VOC2012数据集结果VOC2007数…...

Golang Gorm 创建HOOK
创建的时候,在插入数据之前,想要做一些事情。钩子函数比较简单,就是实现before create的一个方法。 package mainimport ("gorm.io/driver/mysql""gorm.io/gorm" )type Student struct {ID int64Name string gorm:&q…...

计算机视觉的应用15-图片旋转验证码的角度计算模型的应用,解决旋转图片矫正问题
大家好,我是微学AI,今天给大家介绍一下计算机视觉的应用15-图片旋转验证码的角度计算模型的应用,解决旋转图片矫正问题,在CV领域,图片旋转验证码的角度计算模型被广泛应用于解决旋转图片矫正问题,有效解决机…...

【Seata】分布式事务问题和理论基础
目录 1.分布式事务问题 1.1本地事务 1.2分布式事务 2.理论基础 2.1CAP定理 2.1.1一致性 2.1.2可用性 2.1.3分区容错 2.1.4矛盾 2.2BASE理论 2.3解决分布式事务的思路 1.分布式事务问题 1.1本地事务 本地事务,也就是传统的单机事务。在传统数据库事务中…...

文件打包解包的方法
在很多情况下,软件需要隐藏一些图片,防止用户对其更改,替换。例如腾讯QQ里面的资源图片,哪怕你用Everything去搜索也搜索不到,那是因为腾讯QQ对这些资源图片进行了打包,当软件运行的时候解包获取资源图片。…...

npm 清缓存(重新安装node-modules)
安装node依赖包的会出现失败的情况,如下图所示: 此时 提示有些依赖树有冲突,根据提示 “ this command with --force or --legacy-peer-deps” 执行命令即可。 具体步骤如下: 1、先删除本地node-modules包 2、删掉page-loacl…...

sqlserver查询表中所有字段信息
精简 SELECT 字段名 a.name,主键 case when exists(SELECT 1 FROM sysobjects where xtypePK and parent_obja.id and name in (SELECT name FROM sysindexes WHERE indid in( SELECT indid FROM sysindexkeys WHERE id a.id AND colida.colid))) then √ else …...

二叉树的概念、存储及遍历
一、二叉树的概念 1、二叉树的定义 二叉树( binary tree)是 n 个结点的有限集合,该集合或为空集(空二叉树),或由一个根结点与两棵互不相交的,称为根结点的左子树、右子树的二叉树构成。 二叉树的…...

【面试题】智力题
文章目录 腾讯1000瓶毒药里面只有1瓶是有毒的,问需要多少只老鼠才能在24小时后试出那瓶有毒。有两根不规则的绳子,两根绳子从头烧到尾均需要一个小时,现在有一个45分钟的比赛,裁判员忘记带计时器,你能否通过烧绳子的方…...
web vue 项目 Docker化部署
Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段: 构建阶段(Build Stage):…...

深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...

关于nvm与node.js
1 安装nvm 安装过程中手动修改 nvm的安装路径, 以及修改 通过nvm安装node后正在使用的node的存放目录【这句话可能难以理解,但接着往下看你就了然了】 2 修改nvm中settings.txt文件配置 nvm安装成功后,通常在该文件中会出现以下配置&…...

如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...

Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...

Unity UGUI Button事件流程
场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...