当前课程知识点:程序设计基础 > 第八章 非文本数据处理 > 8.3 以二进制文件存储链表 > 8.3.2 代码讲解
那为了方便二进制文件的数据存取
我们重新定义了结构类型
大家看Time_t保持不变
但是我们把原来的Node的节点里头的
那四个成员把它剥离出来
单独的新定义了一个新的结构类型
叫Log_info把那个time
还有id还有op把它保存在里头
而next指针仍然在Node的里头
因为next指针是我们为了组织这些节点
是链表的这个组成部分
跟这个用户的信息没关系
所以我们把它还是放到Node的里头
但是Log_info就是用户的这个信息
我们把它用三个数据成员来保存
那这个Node的节点里头 它就只有两个变量
一个是Log_info定义的变量log
一个是Node*这样的指针next
有了这样一个结构类型的重新定义之后
我们来看看这个主程序的一个代码的修改
那这个main函数的前半部分
跟以前的代码是一样的
我们这里头就把它省略掉了
我们在主程序里头写了
输出哈希表内容然后注意下面是新的
SaveHashTab我们要把它的这个HashTab表的内容
存储到一个文件里去
用二进制的方式去存储它
这个文件加做list.tab
同样的这个名字是你自己取的 你可以任意去取
不是说限定必须叫这个名字
然后我们去释放这个哈希表
把它内存释放掉所以是release
这个跟前面的那个例子是一样的
接着这个哈希表释放空了 那么我们来试一试
从你刚才存的那个二进制文件里头
再把数据读进来看看它的内容是怎样子的
所以我们调用了一个新的函数
这个也是新的叫LoadHashTab
它同样的有两个值第一个表示
把数据load到哪个hash表里去
在我们这里头是list.tab第一个变量
从哪个文件读呢这是第二个变量
在我们这里头是list.tab
就是你刚刚保存的那个二进制文件
接下来我们输出从文件读进来的内容
它的信息到底是什么把它输出来
这样我们就可以对比看看之前操作的那些哈希表
你存起来再从里头读进来是不是一样的
最后我们是把这个hash表的内容释放掉
这个也是以前代码里头出现过的release list tab
那来看新编的这个savehashtab
就是把哈希表的内容存放到一个文件里去
你看哈希表内容存放到文件里去两个参数
所以我们这个函数的参数也很好去找出来
定义两个参数分别表示哈希表和文件的名字
那由于是往文件里写所以我们是输出
因此fout是ofstream来定义的
根据我们前面介绍里头所说的
第一项filename它的参数
第二个参数是ios::binary
表示我要以二进制的方式来写数据
这个不能搞错 搞错了就不对了
接下来hash表有256项
所以我们用个for循环来依次处理每一个表项
在每一个表项它其实是一个有可能是一个链表
所以我们定义一个指针变量p去等于这个hashtab0[i]
然后你看又来了用我们以前介绍的遍历这个方法
所以while(p)p不为空
那有人说如果那个地方是空 空就不做了呗
如果不为空 那我就来把这个节点内容写到文件里去
按照我们前面介绍的方法得用fout去调用write函数
第一项是存放数据的内存的地址 那存到哪里了
这个p指针所指的这个节点大家还记得嘛
那个结构变量里头有一个log这样的数据
就是我们刚刚重新定义结构类型之后把它剥离出来的
所以是p->log 这是一个结构变量的名字
我们得取它地址
取它地址之后这个地址并不是我们所想要的类型
所以我们还得把它转化成字符类型 所以前面是char*
接下来第二项这个结构多大
sizeof p->log
还记得我们以前在介绍这个write函数的时候
说的是sizeof data告诉你说不一定要写成data
你看现在我们代码里头就可以看到
它真的不是data它是p->log
然后是下一项这个叫做依次的递进p=p->next
然后它就循环完了这是一个savehashtab
那么loadhashtab跟这个是对称的类似的
所以它定义这个变量是fin
我们去判断这个fin变量是不是正常的
所以用while fin
这个是fin这个变量它自己会去
变成一个布尔值来回答它是不是正常
如果读到文件尾了它就不正常了
这个while循环就退出了
那循环体的写法是定义一个临时变量data
它是一个Node节点
然后从文件里头读入数据到data.log 这个成员里头去
所以是data.log注意因为data是一个普通的结构变量
所以得用点操作访问它的log数据成员
得到它之后取地址and 然后把它转成char*
这个跟我们前面去write的时候是类似的
接着第二项是它的大小 sizeof data.log
这就是把它读进来那有可能读失败
因为它已经到过列尾了你再读有可能失败
所以我们在读完之后立刻要判断是否成功
所以下面是if fin.eof这个函数
告诉我是不是到了文件尾
是不是已经越过文件这个尾巴了
如果是就说明整个文件已经读完了
我就break不用再while循环了
注意啊 这个break是break的这个while
不用再做while这个循环去读后面的东西了
那如果没到文件尾还可以接着读
那我们就可以说明
刚才读入的这个data log内容是正确的
如果前面的eof返回的false
就说明前面读的fin.read实际上是失败的
是不正确的你就不能把这个不正确的存到hash表里去
所以这个样if这个语句非常重要
只有当它是正确的时候才
意味着前面刚刚读进来的数据是正确的
如果这个文件已经到结尾了那就意味着
前面那个fin.read读进来的实际上不知道是什么
乱七八糟的 所以那个数据不能写
因此那个地方就是if完了就是break
所以如果它没有break说明它没有到文件尾
说明它读的是对的
说明我们需要把这个data送到这个hash表里去
所以我们再一次调用在前一讲里头介绍的
insert hash_tab然后第二个参数是data
这样就把新的节点数据送到里面去了
一轮一轮做下去 直到文件读完所有的内容就退出
这是loadHashTab
这个详细的代码大家从在线平台的讲义区里头下载
-1.1 基础知识
-1.2 买菜问题
-1.3 数学运算
-1.4 补充说明
-1.5 总结
--1.5 总结
-程设论道
--程设论道
-师生问答
-第一章 编程初步--语法自测
-2.1 关于超级计算器的几点思考
-2.2 电子秤模拟 — 背景介绍及需求分析
-2.3 电子秤模拟 — 代码实现
-2.4 变量定义与变量类型
-2.5 猜数游戏与数据表示
-2.6 关于变量的讨论
--公告
-2.7 变量体现的计算思维
-程设论道
--程设论道
-师生问答
--师生问答
-第二章 变量与代数思维--语法自测
-3.1 谁做的好事——语义表示
-3.2 谁做的好事——真假检查
-3.3 谁做的好事——循环枚举
-3.4 谁是嫌疑犯——多重循环枚举
-3.5 谁是嫌疑犯——破案线索表示
-3.6 谁是嫌疑犯——用二进制枚举
-程设论道
--程设论道一
--程设论道二
--程设论道三
-师生问答
-第三章 逻辑推理与枚举解题--语法自测
-4.1 插花游戏
-4.2 筛法
-4.3 线性查找
-4.4 折半查找
--4.4.1 提问
-4.5 排序问题
-4.6 总结
--4.6.1 总结
-程设论道
--程设论道二:筛法
-师生问答
-第四章 筛法与查找--语法自测
-5.1 阶乘
-5.2 排序
-5.3 矩阵填充
-5.4 分书与八皇后
-5.5 青蛙过河
-程设论道
--程设论道一
--程设论道二
-师生问答
--师生问答一
--师生问答二
-第五章 分治思想与递归--语法自测
-6.1 兔子数列问题
-6.2 分鱼问题
-6.3 橱窗的插花问题
-6.4 最长公共子序列问题
-程设论道
--程设论道一
--程设论道二
-师生问答
--师生问答
-第六章 递推与动态规划--语法自测
-7.1 统计记录总数
-7.2 统计活跃用户数
-7.3 统计在线时长
--7.3.2 结构
-7.4 总结
--7.4.1 总结
-程设论道
--程设论道
-师生问答
--师生问答
-第七章 文本数据处理--语法自测
-8.1 将数据组织成链表
-8.2 提高链表访问效率 —— 哈希链表
-8.3 以二进制文件存储链表
-程设论道
--程设论道一
--程设论道二
-师生问答
--师生问答
-第八章 非文本数据处理--语法自测
-9.1 自动售卖程序
-9.2 配制水果信息
-9.3 指定界面语言
-程设论道
--程设论道
-师生问答
--师生问答
-第九章 可配置的程序设计--语法自测