【C语言进阶】文本与二进制操作文件,优化通讯录。

news2024/9/24 11:30:55

前言:

上篇文章,我们已经学习了有关本地磁盘文件的常用文件操作,已经能够对本地文件进行调用与读写。我们磁盘中还存在着一些内容用二进制存储的文件,这也就是我们今天将要讲解的内容。

一、文本文件与二进制文件

根据数据的组织形式,我们将数据文件称为文本文件和而二进制文件

数据在内存中以 二进制的形式存储,如果 不加转换的输出到外存,就是 二进制文件;
如果要求在外存上 以ASCII码的形式存储,则需要 在存储前转换。以ASCII字符的形式 存储的文件就是文 本文件。

那么数据在内存中是如何存储的的呢?

实际上字符在内存中的存储一律是以ASCII码值得形式进行存储的,数值型数据既可以用ASCII码存储,也可以用二进制形式进行存储。例如十进制数字10000在进行存储时,就可以有两种存储形式:

①二进制形式:
00000000 00000000 00100111 00010000
②ASCII码形式:
00110001 00110000 00110000 00110000
1 0 0 0

接着让我们来看看示例:

#include <stdio.h>
int main()
{
    int a = 10000;
    FILE* pf = fopen("test.txt", "wb");
    //wb表示只写模式打开二进制文件
    if (pf == NULL)
    {
        perror(fopen);
    }
    else
    {
        fwrite(&a, 4, 1, pf);//二进制的形式写到文件中
        //将变量a中的数据,每四个字节存储一次,写入文件指针pf指向的文件;
        fclose(pf);
    }
    pf = NULL;
    return 0;
}

上面这段代码运行成功后,我们就已经成功将变量a中的数据写入到本地磁盘对应的txt文件中了,可是我们发现,当我们尝试打开本地文件查看存储的数据时,里面看起来并不是我们所想要的东西:

导致这样的原因是因为我们使用了“wb”方式,即以二进制形式进行了写入,而要查看这部分内容我们只需要将文件添加到vs里面并且将打开方式改为二进制编制器。

具体步骤:选中我们的“源文件”栏右击选择“添加”,“添加现有项”,将写入时创建的txt文件添加进来,然后选中该文件,右击选择"打开方式"接着在选项框中下拉选择“二进制编制器”,此时我们便可以看到文件内的实际存储情况了:

但是这好像也不是我们存储的数据,我们再来看看我的的语句:

fwrite(&a,4,1,pf);

根据这条语句,我们在进行数据写入时,是每次四个字节进行写入的,于是根据其二进制码可以得到它的存储为:

00000000 00000000 00100111 00010000
我们再将它每四个字节分开来:
0000 0000 0000 0000 0010 0111 0001 0000
于是就可以得到:
00 00 27 10

又因为在之前我们就验证过vs采用的是小端存储模式,于是在进行压栈时会将数据进行倒置存储,于是就有:

10 27 00 00

二、文件读取结束的判断:

1.被错误使用feof函数:

在我们日常写代码过程,有很多人都会错误地使用了feof函数,将其用于判断文件是否读取结束,而这种使用方式是错误的。

大家一定要牢记

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

2.判断文件读取结束:

文本文件判断文件读取结束方法:

①使用fgetc函数判断是否为EOF;
②使用fgrts函数判断返回值是否为NULL;

例如:

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int c;// 注意:int,非char,要求处理EOF
    FILE* fp = fopen("test.txt", "r");
    if (!fp)
    {
        perror("File opening failed");
        return 1;
    }
    //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);
    fp = NULL;

    return 0;
}

二进制文件判断文件读取结束方法:

使用fread函数判断返回值是否小于实际要读取的数据个数

例如:

#include <stdio.h>
enum { SIZE = 5 };
int main()
{
    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);
    fp=NULL;
}

三、文件缓冲区:

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

这边可以通过代码来验证缓冲区:

#include <stdio.h>
#include <windows.h>
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/400313.html

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

相关文章

SpiderFlow爬虫获取网页节点

SpiderFlow爬虫获取网页节点 一、SpiderFlow 文档地址&#xff1a;https://www.spiderflow.org/ 二、问题&#xff1a;获取一篇文章的标题、来源、发布时间、正文、下载附件该怎么获取&#xff1f; 举例&#xff1a;【公示】第三批智能光伏试点示范名单公示 三、抓取网页步骤…

Heatmap-based Out-of-Distribution Detection 论文阅读

原文地址 概要 我们的工作将分布失调【out-of-distribution,OOD】检测作为神经网络输出解释问题进行研究。我们学习了一种热图【heatmap】表示&#xff0c;用于检测OOD图像&#xff0c;同时可视化ID和OOD的图像区域。给定一个训练过的固定分类器&#xff0c;我们训练一个解码…

ArrayList源码分析(JDK17)

ArrayList类简介类层次结构构造无参构造有参构造添加元素add&#xff1a;添加/插入一个元素addAll:添加集合中的元素扩容mount与迭代器其他常见方法不常见方法不常见方法的源码和小介绍常见方法的源码和小介绍积累面试题ArrayList是什么&#xff1f;可以用来干嘛&#xff1f;Ar…

funkyheatmap | 用这个包来完美复刻Nature Biotechnology的高颜值神图吧!~

1写在前面 天气开始暖和了☀️&#xff0c;发现旅游的人好多啊&#xff01;~&#x1f972; 不知道自己什么时候能有时间出去看看外面的世界&#xff0c;实在是太忙了。&#x1f637; 最近用到的有个包感觉很不错&#xff0c;分享给大家&#xff0c;funkyheatmap包。&#x1f61…

进程与多线程(入门)

什么是线程 要了解什么是线程&#xff0c;得先知道什么是程序。 程序&#xff1a;为完成特定任务&#xff0c;用某种语言编写的一组指令的集合。 例如&#xff0c;QQ&#xff0c;Steam&#xff0c;亦或者java写的helloword。 这些都是程序 了解了程序&#xff0c;还得清楚什么…

d3.js绘制饼状图,悬浮出现字以及点击事件

代码以及注释如下&#xff1a; const width 300; // 定义圆的宽度 const height 300; // 定义圆的高度 const radius Math.min(width, height) / 2; // 算出半径 const color d3.scaleOrdinal() .range(["#98abc5", "#8a89a6", "#6b486b&qu…

【MySQL高级篇】第05章_存储引擎

第05章_存储引擎 1. 查看存储引擎 查看mysql提供什么存储引擎 show engines;2. 设置系统默认的存储引擎 查看默认的存储引擎 show variables like %storage_engine%; #或 SELECT default_storage_engine;修改默认的存储引擎 如果在创建表的语句中没有显式指定表的存储引擎…

一分钟成为签到达人!Redis BitMap轻松解决,Spring Boot带你飞

如何实现签到功能&#xff0c;尤其是如何实现高效的签到与统计&#xff0c;是开发者们需要考虑的问题。在本篇文章中&#xff0c;我们将介绍如何利用Spring Boot整合Redis BitMap实现签到与统计。 Redis BitMap简介 在介绍如何利用Redis BitMap实现签到与统计之前&#xff0c;…

unity动画--动画绑定,转换,用脚本触发

文章目录如何制作和添加动画大概过程示例图将多组图片转化为动画放在对象身上实现动画之间的切换使用脚本触发Parameters(Trigger)如何制作和添加动画 大概过程示例图 将多组图片转化为动画放在对象身上 首先&#xff0c;我们要为我们要对象添加animator 然后我们要设置对应的…

计算机网络-应用层

文章目录前言概述Https协议(443)Http协议(80)HttpsTLS/SSL 协议TLS的四次握手总结前言 本博客仅做学习笔记&#xff0c;如有侵权&#xff0c;联系后即刻更改 科普&#xff1a; 概述 Https协议(443) 参考网址 Http协议(80) 谈到Https必然要先将httpHTTP 请求报文结构 请求…

谷粒学院开发(一):基础准备

商业模式 常见商业模式 B2C模式&#xff1a; 两个角色&#xff1a; 管理员&#xff1a;增加&#xff0c;修改&#xff0c;删除普通用户&#xff1a;查询 商家到用户&#xff0c;自己制作大量自有版权的视频&#xff0c;放在自有平台上&#xff0c;让用户付费。 这是这个项目使…

Linux下查看图片中某点的像素X、Y坐标

在做目标检测、目标追踪的任务过程中&#xff0c;我们会用到一些开源的数据集&#xff0c;比如MOT16多目标追踪数据集。这些数据集会提供数据标注文件gt.txt,里面的内容如下1,1,912,484,97,109,0,7,12,1,912,484,97,109,0,7,13,1,912,484,97,109,0,7,14,1,912,484,97,109,0,7,1…

[Openwrt]procd实现hotplug机制介绍

Linux处理hotplug事件方法kobject_uevent() 产生 uevent 事件(lib/kobject_uevent.c 中), 产生的 uevent 先由 netlink_broadcast_filtered() 发出, 最后调用 uevent_helper[] 所指定的程序来处理.uevent_helper[] 里默认指定 "/sbin/hotplug", 但可以通过 /sys/kern…

spring boot starter 实现生成行为验证码验证

最近公司有一个验证用户行为的需求&#xff0c;因此实现了一个用户行为验证码的starter&#xff0c;具体效果如下&#xff1a;代码结构如下&#xff1a;common 下面放的是公共文件枚举类generator 下面放的是生成行为验证码的相关类与扩展接口resource 下面放的是加载解析行为图…

若依代码生成器的使用

一、代码生成器的使用1.新建maven模块原则上&#xff0c;我们的业务代码和若依系统本身的系统代码是要做隔离的&#xff0c;一方面是易于之后随着若依系统升级而升级&#xff0c;另一方面则是纯粹的合理性考虑。这里新建一个ruoyi-business模块作为业务代码模块&#xff0c;新建…

Mac环境安装python

一、介绍&#xff1a; Python是跨平台的&#xff0c;它可以运行在Windows、Mac和各种Linux/Unix系统上。在Windows上写Python程序&#xff0c;放到Linux上也是能够运行的。 要开始学习Python编程&#xff0c;首先就得把Python安装到你的电脑里。安装后&#xff0c;你会得到Pyt…

LearnOpenGL-光照-4.光照贴图

本人刚学OpenGL不久且自学&#xff0c;文中定有代码、术语等错误&#xff0c;欢迎指正 我写的项目地址&#xff1a;https://github.com/liujianjie/LearnOpenGLProject 文章目录光照贴图漫反射贴图例子1镜面光贴图例子2 采样镜面光贴图小结什么是光照贴图光照贴图如何影响颜色光…

开源一个通用的 HTTP 请求前端组件

像 Postman 这样可视化的 HTTP 请求工具是调试 API 不可或缺的利器。Postman 虽好但也越来越重&#xff0c;而且如果要整合到其他工具中&#xff0c;显然 Postman 又不是一个可行的方案。于是我想打造一个简单的前端组件&#xff08;widget&#xff09;&#xff0c;它是一个标准…

天池 DeepRec CTR 模型性能优化大赛 - 夺冠技术分享

作者&#xff1a;niceperf 团队 (李扬, 郭琳) 大家好&#xff0c;我们是 niceperf 团队&#xff0c;在天池 DeepRec CTR 模型性能优化大赛中&#xff0c;很荣幸取得了冠军的成绩 (Top 1/3802)。这篇文章复盘一下我们的参赛经验&#xff0c;希望对大家有所启发。 1.背景介绍 …

KDZD5035系列电缆试验油杯

一、概述 武汉凯迪正大总结十多年的局放试验经验&#xff0c;开发生产了KDZD5035系列电缆试验油杯终端&#xff0c;具有使用方便&#xff0c;性能可靠&#xff0c;本身局放量小等优点&#xff0c;与早期落地式油杯相比&#xff0c;可为用户节约大量的试验成本。 KDZD5520交流…