IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> ★C语言进阶★ 文件操作图文详解,初学者也能看懂(上) -> 正文阅读

[C++知识库]★C语言进阶★ 文件操作图文详解,初学者也能看懂(上)

本篇包含一下几个方面:

1. 为什么使用文件

2. 什么是文件

3. 文件的打开和关闭

4. 文件的顺序读写

1.为什么使用文件

当我们打开任何一个程序的时候,程序运行,跑起来,然后关闭,这就是一套的流程,我们在程序跑起来的时候过程那些产生的文件,全都会在程序关闭的时候销毁,这就引发一个问题,如果这些数据很重要,我希望它能保留下来,那我就得找个地方把它存起来,这个时候我们就需要文件了。

2.什么是文件

磁盘上的文件是文件。
但是在程序设计中,我们一般谈的文件有两种:程序文件、数据文件(从文件功能的角度来分类的)。
这里我举个例子方便理解:
程序文件
包括源程序文件(后缀为 .c , 目标文件( windows 环境后缀为 .obj , 可执行程序( windows 环境
后缀为 .exe )。

以这个举例子,我创建了一个project4的文件,在里面随便写了点东西,在之后的程序文件里面就可以发现这样的一个.c后缀名的文件,这个就是原程序文件。

同样,在这里还可以翻到一个应用文件,如图:

?这些都是我们所说的程序文件。

那什么是数据文件呢?

数据文件
文件的内容不一定是程序,而是程序运行时读写的数据,比如程序运行需要从中读取数据的文
件,或者输出内容的文件。
举个例子
我创建了一个程序,叫test.c,然后我又创建了个文本,叫date.txt,我通过程序在date里面放了一堆数据,然后再之后调用date读取里面的数据,那这里的date就叫数据文件。
文件名
一个文件要有一个唯一的文件标识,以便用户识别和引用。
文件名包含 3 部分:文件路径 + 文件名主干 + 文件后缀
例如: c:\code\test.txt
这个意思就是在c盘的code目录下面有一个文件,文件名是test.txt
为了方便起见,文件标识常被称为 文件名,这个地方就不多讲。
文件的打开和关闭
文件指针
缓冲文件系统中,关键的概念是 文件类型指针 ,简称 文件指针
每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名
字,文件状态及文件当前的位置等)。这些信息是保存在一个结构体变量中的。该结构体类型是有系统
声明的,取名 FILE .
这里为了方便理解,我举个例子,你想喝水的时候,是不是要先拿起水瓶拧开瓶盖,然后喝掉里面的水,等喝完了水再把瓶盖盖起来?这里就是同理。

如果你有兴趣,可以打开vs看看这个FILE里面到底是什么东西,这里以我的vs2013示范:

struct _iobuf {
? ? ? ? char * _ptr ;
? ? ? ? int ? _cnt ;
? ? ? ? char * _base ;
? ? ? ? int ? _flag ;
? ? ? ? int ? _file ;
? ? ? ? int ? _charbuf ;
? ? ? ? int ? _bufsiz ;
? ? ? ? char * _tmpfname ;
? ? ? };
typedef struct _iobuf FILE ;

可以看到它创建了一个结构体,结构体名字是_iobuf ,包含了一丢的数据类型,char* 、int,最后用typedef重命名。

那我们要不要考虑这个结构体怎么用呢?

不用担心,当打开文件的时候系统会自动往里面填充数据,直接用就好了。?

我们可以创建一个FILE类型的指针变量,就跟创建其他指针一样:

FILE* p;

这个指针可以指向数据内存中的某一个文件,对其进行操作,也就是说:通过文件指针变量能够找到与它关联的文件

文件的打开和关闭

就好像你喝完水瓶子要重新盖好一样,文件打开完后也是要关闭的,ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件。

fopen

从上面的图我们可以看到,当我们运用fopen函数的时候有好几种模式,每个模式对应有不同的效果。

?这里说一下,fopen的返回值是一个指针,指针指向的是要操作的文件,如果返回的是一个空指针,则说明打开的时候遇到了错误。

示范如下:

这是很简单的代码,打开text.txt文件,以?只写?的形式打开。

ps:

只读 指的是将文件中的数据读取到程序内部。

只写 指的是将程序运行的数据写入到文件里。

这是目前的项目栏?

我们让程序跑起来:

?

?我们可以看到多出来一个text的文件,这个就是fopen创建出来的一个文本文件。

再示范一下,这次我们拿 "r" ,对于文件的只读形式来试试:

这里我让程序打开一个叫txtt.txt的文件,这个文件是不存在的,那会发生什么呢?

程序先是跑起来了,再之后蹦出弹屏告诉我失败,这就是以只读的形式打开不存在的文件报的错,要多多注意。

其他我就不一一列举了,有兴趣的可以自己下来尝试一下。?

在打开完文件之后,别忘了要关闭文件,用到fclose:

这个用起来就简单多了,:

? fclose (pf );
那整串代码连起来,就是这样:

?在关闭了文件之后,别忘了将pf置成空指针。

文件的顺序读写

? ? ? ? 如果你想在程序里面随便写数据,想在哪写就在哪写,那叫做随机读写,当然,也可以一个字符一个字符的写进去,这叫顺序读写。

这里我们就一个一个说明,让大家了解的更加透彻

??fgetc?

? fputc

我们可以将这两个函数一起用,先写入字符,再读取字符,做个示范:

将字符abc写入到数据里面,我们让程序跑起来:

打开文件:

?

可以看见abc已经被我们写进date.txt的文件里面去了,那我们不妨一次多写几个:

再次运行程序,随后打开文件查看效果:

可以看到从a到z的字符都被我们写入到文件里面去了,跟我们想的一样。

但我们回过头来看,fput适用于所有输出流,那什么是输出流呢?

我们在用fputc的时候,先要打开文件,再写入信息,再关闭文件,但如果我们要打印到屏幕上去呢?那肯定不是打开屏幕,打印上去,关闭屏幕这样的流程,所以这里我们就得了解一下C语言程序在运行的时候,它默认打开的三个流:

stdin - 标准输入流

stdiout - 标准输出流

stderr - 标准错误流

每一个程序运行起来都会默认运行这三个流,当我们要从键盘上读取的时候,其实是从标准输入流里面去读取,就不用再打开了,当我们要打印信息的时候,就是从标准输出流里面去读取到屏幕上去。

所以我们在用printf这样的函数的时候,这个标准输出流就已经打开了,所以printf就可以直接打印在屏幕上去。

那我们刚刚看fputc适用于所有输出流,那适不适用这个标准输出流呢?

是适用的,标准输出流也是输出流,因为stdin stdiout stderr 都是FILE类型的,所以当我们想读取文件打开文件的时候,传参都是直接将FILE*的指针传过去,我们可以将pf换成stdiout,将我们想写入的信息直接在屏幕上打印出来:

?当你写成pf的时候,写到文件里面去了,就叫文件流。

既然写文件我们了解了,那我们就来读文件

fputc返回的时候,返回的是int型或者是EOF,也就是说它正常读取的时候返回的是ascll码值,所以我拿一个整型接收:

?这里我拿整型ch接收再打印出来,第一次我们读取的应该是a,第二次是b,第三次是c,那程序跑起来,我们看看效果:

可以看到它运行的效果跟我们想的一样 ,但是这里要注意一个事项,就是我们第一次读取的时候它指向的是a,第二次它指向的就不是a了,它会往下走一个字符,指向b,第三次它指向的就是c了:

这里还有一点要注意的,这里ch能不能用char类型?

答案是否定的,不行,因为fgetc读取的还有一个EOF,而EOF的值是-1,如果拿char类型接收会出现错误,请注意。

但是每次读取一个字符,太慢了,我们能不能一次读取一行呢?

可以,这里就要用到另外两个函数:

fgets fputs

这里我放上两个函数的信息:

我们直接看代码:

这里直接写入一串代码进去,我们让程序跑起来:

我们打开文件看看 :

跟我们所想一样,成功将字符串写入文件 ,那我们在写一串试试:

让程序跑起来,我们再次打开文件:

这里可以看见第二次写入的字符串直接接到了第一串的后面,并没有换行,除非我们自己加上换行。

?既然可以写入一行,那我们也可以读取一行,用到fgets函数:

这里就可以看到fgets函数的适用,第一个参数指你要放到哪里去,第二个是放多少字符进去,第三个是读取的地址。

?此时我将文件内容修改一下:

我将0.0换至第二行;

再看看效果:

可以看到即使我让它读取100个字符,但它还是只显示了第一行,我们让程序读两次看看;

这次就成功将两行都读取了出来 。

但是如果我们让它一次读取的个数小于我们的字符串长度呢?

这次我们一次读取3个字符,但屏幕上打印的却只有两个

?我们再读取一次,看看效果:

可以看到它一次只读取两个字符,?这就是fgets读取的一个方式,这里要注意,如果fgets返回值,如果为空,那就是读取结束或者是读取出现错误。

我们了解了fgets之后,我们能不能实现复杂一点的,比如说我这里有两个文本,第一个text是我目前写的代码文件,而data2是我的目标文件(这里还没有创建),我想将data的内容拷贝放到data2里面,能否实现这样一个功能?

?

当然可以,让我们逐步来实现这个功能;

我们先以只读的形式打开data.txt,随后判断是否读取到东西,如果pf为空指针,则显示错误代码,随后我们以只写的形式打开data2.txt,如果当前目录没有data2,则创建一个data2.txt的文件,同样,如果报错就打印错误代码,随后我们开始拷贝,跟之前代码相同,我们循环读取,直到pf所指向的data.txt没有信息就停下,此时打印完成,我们关闭pf和pw指向文件,并将其置为空指针。

程序成功跑了起来,我们打开文件看看效果:

可以看到信息一致,我们成功将data.txt的文件拷贝放置data2.txt下。?

?这里还要提一下,如果在写信息的时候提前关闭了文件,那信息是写不进去的。

格式化输入函数? fscanf? 所有输入流

格式化输出函数? fprintf? ?所有输出流

现在,我们读取字符已经没问题了,读取字符串也没问题了,但是如果我说读取一个结构体呢?

这里就要用到上面提到的格式化输入函数,我们将其与printf对比:

????????可以看到在声明中,它们后两个参数是一样的,不同的是fprintf多了一个FILE*的指针,那我们怎么使用这个fprintf呢?

很简单,在printf参数前面多加一个FILE指针就好了,示范一下:

当程序运行起来,我们再次打开文件查看的时候,文件里面的数据变成了:?

我们成功将格式化的数据写入到文件中。

既然fprintf如此简单,那fscanf怎么样呢?

我们来看看对比;

可以看到,它也仅仅比scanf多一个FILE*的指针,跟fprintf与printf的对比一样,那我们如何使用fscanf这个函数呢?

既然明白了fprintf与printf的对比,那fscanf也不在话下。

只需在前面加一个从哪里读取即可。?

也就是说,我们可以按照某种格式将信息放到文件里面去,也可以按照某种格式从文件里面读取相对应的信息。

那我们还剩下:

二进制输入 ? ? ? ? ? ? ? ? ? ? ? ? fread ? ? ? ? ? ? ? 文件
二进制输出 ? ? ? ? ? ? ? ? ? ? ? ? fwrite ? ? ? ? ? ? ?文件

我们先从写开始,同样,来看一下函数参数信息:

我们拿代码说话:

我们创建一个结构体数组,里面有两个人的信息,我们现在按照二进制wb的形式写进去,从s的地址将里面的两个元素以二进制的形式写到pf指向的date.txt里面,我们让程序运行起来看效果:

?成功写了进去,那我们打开文件看看里面放的信息;

哎?这是什么东西,怎么看不明白?

这就是我们二进制形式写进去的信息,我们读不懂也正常,但我们既然写进去了,但自然可以打开,我们先了解一下fread函数:

?可以看到参数跟fwrite相似,其功能则是从FILE*指向的文件里面,读size个信息放到目标里去。

看看代码:

?这就是以二进制的形式写进去,以二进制的形式打开。

那目前位置,我们已经明白了下面这三个相似的函数,那它们之间主要的区别是什么?

我们看到最后有叫sscanf和sprintf的函数,这两个函数是什么呢?

我们不妨看一下函数参数;

?如果它与前面fscanf fprintf相对比,其实只是差一个FILE*的指针,那这是因为什么?

fprintf是将后面的文件格式化的写到某个流里面去,而sprintf是将后面的格式化数据直接转换成字符串。

看代码:

这里我们用sprintf直接将一个结构体变成了字符串类型,再将其打印出来。

那既然我们可不可以再从这个字符串里面读取信息还原我们的信息呢??

?当然可以,看看代码:

对比结论:

?

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-02-22 20:23:18  更:2022-02-22 20:25:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 7:50:06-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码