【C语言】文件操作(上卷)

2024-06-02 05:44
文章标签 语言 操作 上卷

本文主要是介绍【C语言】文件操作(上卷),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

为什么要使用文件呢?

你是否发现,我们写的程序,退出后再次运行,是记不住上次程序的数据的。这是因为我们写的程序是存储在电脑的内存中的,如果程序退出,内存回收,所以数据就丢失了。

如果想要将数据进行持久化的保存,我们可以使用文件。

想想我们电脑上的这些文件,PPT之类的,我们写好后再次打开依然是在的。包括我们写好的代码,也在电脑的文件夹里放着。这是因为这些文件是放在电脑的硬盘上的。

硬盘上的数据除非自己修改,否则是不会丢的。下次打开程序还是在硬盘上拿到我们的数据。

 所以当我们把数据放在文件中,文件又放在硬盘上,就可以将数据进行持久化的保存。

 当然这个“持久”,也不是永久,电脑或者硬盘是可能坏的。

什么是文件?

磁盘(硬盘)上的文件是文件。

我们电脑的C、D盘里进去的这些都是文件。

但在程序设计中,我们一般谈论的文件有两种:程序文件和数据文件(从文件功能的角度来分的)。

程序文件

程序文件包括源程序文件(后缀为.c),目标文件(windows环境后缀为.obj),可执行程序(windows环境后缀为.exe)。

数据文件

文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文件,或者输出内容的文件。

比如在下图中,我们的test.exe可以从data.text中读取数据(读),或输出数据到data.txt(写)中,我们的test.exe是程序文件,data.txt是数据文件。

本文主要探讨的是数据文件,也就是怎么通过C语言写代码来操作数据文件。

以前,我们处理数据的输入输出都是以终端(也就是我们运行起来看见的黑框)为对象的,即从终端的键盘输入数据,运行结果显示在显示器上。

我们用printf打印数据到终端或者说屏幕,其实就是的动作。

而从终端或屏幕输入或者读取数据,就是的动作。

有时我们会把信息输出到磁盘上,当需要的时候再从磁盘上把数据读取到内存中使用,这里处理的就是磁盘上文件。 

经过本文的学习,以后我们写代码就可以将数据写到数据文件里。

文件名

一个文件要有一个唯一的文件标识,以便用户识别和引用。

文件名包含三个部分:文件路径+文件名主干+文件后缀

如:c:\code\test.txt中,c:\code\是路径,test是文件名主干,.txt是文件后缀。

方便起见,文件标识常被称为文件名。

前面是从功能的角度来讲,分为程序文件和数据文件,其实从内容的角度来讲,文件又可以分为二进制文件和文本文件。

二进制文件和文本文件

根据数据的组织形式,数据文件被称为文本文件或二进制文件。

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

我们写上一个代码,它在内存中是以二进制存储的。

比如:

int main()
{int a = 2077;//2077的补码的二进制序列return 0;
}

我们2077的存储方式是在内存中存它的补码的二进制序列。

浮点数在内存中存储也是以二进制。

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

一个数据在文件中是怎么存储的呢?

字符一律以ASCII形式存储,数值型数据可以用ASCII形式存储,也可以用二进制形式存储。

字符没有办法,就只能以ASCII码形式存储。

现在有一个整数10000,如果以ASCII形式输出到磁盘,则磁盘中占用5个字节(每个字符占用一个字节),而二进制形式输出,则在磁盘上只占4个字节(整数的存储占用4个字节)。

注意:并不总是以二进制形式存储占用空间更少的,比如存1的时候,ASCII形式只占用1个字节,而二进制形式存储还是占用4字节。总之,要看具体情况。

具体点分析,10000的二进制序列:

0000 0000 0000 0000 0010 0111 0001 0000

按字节来排着看就是:

00000000 00000000 00100111 00010000

而将10000转换为ASCII形式存储,就是将其转换为1 0 0 0 0的分别存储,各自存储到一个字节(8bit)中去:

00110001 00110000 00110000 00110000 00110000
1        0        0        0        0

(下面是要存的字符,上面是这个字符的ASCII码值的二进制序列。1的ASCII码值是49,49的二进制序列是00110001;0的ASCII码值是48,二进制序列是00110000)

演示:

现在我们创建一个文件,重命名为test.txt

 

以这样的形式存放的时候,存的就是5个字符

这就是文本文件 ,也就是说我们用肉眼能够看得懂的。

现在,我们还可以用代码的方式造出一个二进制文件:

#include<stdio.h>
int main()
{int a = 10000;FILE* pf = fopen("test.txt", "wb");//打开文件test.txt,//w代表write,写。b代表binary,二进制。也就是二进制写的方式来打开文件fwrite(&a, 4, 1, pf);//二进制的形式写到文件中,//写a(提供的是地址),写4个字节,写1次,写到pf关联的文件中fclose(pf);//关闭文件pf = NULL;return 0;
}

然后运行这个程序。

然后找到我们的test.txt,点击编辑:

 所以可以看到,以文本文件的形式来解读我们写进去的二进制时,没法解读。

 怎么证明它是个二进制呢?也可以证明一下:

右击源文件,添加现有项,将我们的test.txt加入。

 

然后再打开方式里选择二进制编辑器。

 

 左侧的00000000不用看,右侧的才是文件内容。

刚才我们已经看到10000的二进制序列:

00000000 00000000 00100111 00010000

十六进制是:

0000 0000 0000 0000 0010 0111 0001 0000
0    0    0    0    2    7    1    0
00 00 27 10

因为是正整数,所以原码、反码、补码相同。但是是小端字节序存储,所以在内存中存的应该是:

10 27 00 00

 所以就是将内存里的数据不加转换直接放到文件里去了。这种文件就是二进制文件。二进制通过文本编译器打开是读不懂的。(vscode打开也不行)

在介绍文件的打开和关闭之前,还有需要铺垫的基础知识:

流和标准流

程序的数据需要输出到各种外部设备,比如我们可以把数据放到文件、光盘、软盘(早期)、U盘、网络、屏幕上等。 

也需要从外部设备获取(读取)数据。

不同的外部设备的输入输出操作各不相同,为了方便程序员对各种设备进行方便的操作,我们抽象出了的概念。

写程序只要关注的操作就可以了,程序先写到流里,流再对接各种各样的外部设备。

可以把流想象成流淌着字符的河。

至于流怎么把数据给这些外部设备,就是底层的事情了。

C程序针对文件、画面、键盘等的数据输入输出操作都是通过流操作的。

一般情况下,我们想要向流里写数据,或者从流中读取数据,都是要打开流,然后操作

一般的三个步骤:

1.打开流

2.读/写

3.关闭流

 

标准流

针对不同的外部设备,流分为很多种,有文件流、标准流等。

可以回想一下我们平时写代码:

scanf,从键盘上取数据;printf,将数据到屏幕上。我们的键盘和屏幕也是外部设备,但是好像并没有打开流这样的具体操作。为什么呢?

这是因为C语言程序在启动(运行)的时候,默认打开了3个流:

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

stdout——标准输出流,在大多数环境就是我们的显示器界面(屏幕),printf函数就是将信息输出到标准输出流中。

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

 这三个流是默认打开的,所以我们在使用scanf、printf等函数时直接就对标准流进行了操作,并没有去关心这个流怎么打开。

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

 C语言中,就是通过FILE*的文件指针来维护流的各种操作的

通过文件指针,我们就能找到流,然后再通过流的操作,操作外部设备。

到此,文件操作(上卷)就结束了,之后还会有文件操作(下卷),祝阅读愉快^_^

这篇关于【C语言】文件操作(上卷)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1023141

相关文章

Python实现对阿里云OSS对象存储的操作详解

《Python实现对阿里云OSS对象存储的操作详解》这篇文章主要为大家详细介绍了Python实现对阿里云OSS对象存储的操作相关知识,包括连接,上传,下载,列举等功能,感兴趣的小伙伴可以了解下... 目录一、直接使用代码二、详细使用1. 环境准备2. 初始化配置3. bucket配置创建4. 文件上传到os

mysql表操作与查询功能详解

《mysql表操作与查询功能详解》本文系统讲解MySQL表操作与查询,涵盖创建、修改、复制表语法,基本查询结构及WHERE、GROUPBY等子句,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随... 目录01.表的操作1.1表操作概览1.2创建表1.3修改表1.4复制表02.基本查询操作2.1 SE

Go语言中nil判断的注意事项(最新推荐)

《Go语言中nil判断的注意事项(最新推荐)》本文给大家介绍Go语言中nil判断的注意事项,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1.接口变量的特殊行为2.nil的合法类型3.nil值的实用行为4.自定义类型与nil5.反射判断nil6.函数返回的

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁

c++中的set容器介绍及操作大全

《c++中的set容器介绍及操作大全》:本文主要介绍c++中的set容器介绍及操作大全,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录​​一、核心特性​​️ ​​二、基本操作​​​​1. 初始化与赋值​​​​2. 增删查操作​​​​3. 遍历方

MySQL追踪数据库表更新操作来源的全面指南

《MySQL追踪数据库表更新操作来源的全面指南》本文将以一个具体问题为例,如何监测哪个IP来源对数据库表statistics_test进行了UPDATE操作,文内探讨了多种方法,并提供了详细的代码... 目录引言1. 为什么需要监控数据库更新操作2. 方法1:启用数据库审计日志(1)mysql/mariad

springboot如何通过http动态操作xxl-job任务

《springboot如何通过http动态操作xxl-job任务》:本文主要介绍springboot如何通过http动态操作xxl-job任务的问题,具有很好的参考价值,希望对大家有所帮助,如有错... 目录springboot通过http动态操作xxl-job任务一、maven依赖二、配置文件三、xxl-

Go语言代码格式化的技巧分享

《Go语言代码格式化的技巧分享》在Go语言的开发过程中,代码格式化是一个看似细微却至关重要的环节,良好的代码格式化不仅能提升代码的可读性,还能促进团队协作,减少因代码风格差异引发的问题,Go在代码格式... 目录一、Go 语言代码格式化的重要性二、Go 语言代码格式化工具:gofmt 与 go fmt(一)

Oracle 数据库数据操作如何精通 INSERT, UPDATE, DELETE

《Oracle数据库数据操作如何精通INSERT,UPDATE,DELETE》在Oracle数据库中,对表内数据进行增加、修改和删除操作是通过数据操作语言来完成的,下面给大家介绍Oracle数... 目录思维导图一、插入数据 (INSERT)1.1 插入单行数据,指定所有列的值语法:1.2 插入单行数据,指

SQL中JOIN操作的条件使用总结与实践

《SQL中JOIN操作的条件使用总结与实践》在SQL查询中,JOIN操作是多表关联的核心工具,本文将从原理,场景和最佳实践三个方面总结JOIN条件的使用规则,希望可以帮助开发者精准控制查询逻辑... 目录一、ON与WHERE的本质区别二、场景化条件使用规则三、最佳实践建议1.优先使用ON条件2.WHERE用