C++中使用boost库存取ini结构化文本文件
off999 2024-11-13 11:48 21 浏览 0 评论
包含如下内容的文件dora.ini存储了学号为20210426的某同学的姓名、年龄、以及已修三门课程的名称和分数。这种名为ini的文件格式可以很方便地存储结构化的对象信息。相较于自行设计文本文件的内容结构,直接使用ini格式既方便,扩展性又好。本实践中,我们借助于大名鼎鼎的boost库来解析ini文件。
[basic]
sNo=20210426
sName=Dora Chen
iAge=17
[scores]
size=3
sName_0=C++
iScore_0=97
sName_1=Calculus
iScore_1=70
sName_2=Economics
iScore_2=65知识产权协议
允许以教育/培训为目的向学生或受众进行免费引用,展示或者讲述,无须取得作者同意。 不允许以电子/纸质出版为目的进行摘抄或改编。 |
在实践中,我们经常需要借助类和对象来表示一个个的实体,例如学籍管理系统中的学生、医疗档案管理系统中的病人。请看如下数据结构:
class Score {
public:
string sName; //课程名称
int iScore; //分数
};
class Student {
string sNo; //学号
string sName; //姓名
int iAge; //年龄
vector<Score> scores; //成绩表
}在这个数据结构中,一个Student对象代表一个学生,其有学号、姓名、年龄等属性;另外还有一个类型为向量的属性scores,该属性存储了学生0到多门已修课程的成绩对象,该对象有课程名称及分数两个属性。
现在考虑将Student对象序列化(保存)到一个文本文件里。在这个数据结构里,一个学生有多少门已修课程是不确定的。对于这种带有不确定性的甚至预期可能发生改变(比如增加性别属性)的数据结构,编程者自行组织文件的存储格式面临诸多不便:①繁琐;②未来数据结构改变时,调整困难。
有一种称之为ini的文本文件结构特别适合存储此种数据结构。ini是initialization(初始化)的简写,这种文件本来的用途是用于存储软件的配置信息,但有也人(比如作者)喜欢借用这个结构来序列化对象。
接下来,我们通过boost库的ini_parser模块来完成ini文件的存储和解析。在介绍C++程序StudentInfo之前,我们先展示StudentInfo所保存出来的dora.ini文件的内容。
[basic]
sNo=20210426
sName=Dora Chen
iAge=17
[scores]
size=3
sName_0=C++
iScore_0=97
sName_1=Calculus
iScore_1=70
sName_2=Economics
iScore_2=65容易看出,ini文件最基本的信息形式为key=value。等号左边为键(key),右边为值(value)。dora.ini分为两个部分,[basic]部分用于存储学号、姓名和年龄,[scores]部分则用于存储全部已修课程的成绩信息。键size=3表明存储了三门课的成绩,由于每门课都有课程名称和分数,为消除歧义,故使用sName_i来表示第i门课的课程名称,iScore_i来表示第i门课的分数。
??C++程序StudentInfo先是创建了用于表示Dora Chen的学生对象dora1,并为其添加了C++、微积分、经济学三门课程的成绩;然后将该对象序列化存储至文件dora.ini;然后再从dora.ini读取其内容至学生对象dora2并打印出来。完整代码如下:
//Project - StudentInfo
#include <iostream>
#include <vector>
#include <iomanip>
#include <boost/property_tree/ini_parser.hpp>
#include <boost/property_tree/ptree.hpp>
using namespace std;
class Score {
public:
string sName; //课程名称
int iScore; //分数
Score(const string& name, const int score){
sName = name;
iScore = score;
}
};
class Student {
string sNo; //学号
string sName; //姓名
int iAge; //年龄
vector<Score> scores; //成绩表
public:
Student(){}
Student(const string& no, const string& name, const int age){
sNo = no; sName = name; iAge = age;
}
void addScore(const string& name, const int score){
scores.emplace_back(name,score);
}
void save(const string& sFile){
boost::property_tree::ptree s;
s.put("basic.sNo",sNo);
s.put("basic.sName",sName);
s.put("basic.iAge",iAge);
s.put("scores.size",scores.size());
for (unsigned int i=0;i<scores.size();i++){
auto& r = scores[i];
s.put(string("scores.sName_")+std::to_string(i),r.sName);
s.put(string("scores.iScore_")+std::to_string(i),r.iScore);
}
boost::property_tree::ini_parser::write_ini(sFile,s);
}
void load(const string& sFile){
boost::property_tree::ptree s;
boost::property_tree::ini_parser::read_ini(sFile,s);
sNo = s.get("basic.sNo","");
sName = s.get("basic.sName","");
iAge = s.get("basic.iAge",0);
scores.clear();
auto size = s.get("scores.size",0);
for (auto i=0;i<size;i++){
auto sName = s.get(string("scores.sName_")+std::to_string(i),"");
auto iScore = s.get(string("scores.iScore_")+std::to_string(i),0);
scores.emplace_back(sName,iScore);
}
}
void output(ostream& o){
o << left;
o << setw(10)<<"No."<<setw(15)<<"Name"<<setw(6)<<"Age"<<endl;
o << "-------------------------------" << endl;
o << setw(10)<<sNo<<setw(15)<<sName<<setw(6)<<iAge<<endl;
o << "-------------------------------" << endl;
for (auto& s:scores)
o << setw(25) << s.sName << setw(6) << s.iScore << endl;
}
};
int main() {
Student dora1("20210426","Dora Chen",17);
dora1.addScore("C++",97);
dora1.addScore("Calculus",70);
dora1.addScore("Economics",65);
dora1.save("dora.ini"); //保存对象dora1至文件dora.ini
Student dora2;
dora2.load("dora.ini"); //从文件dora.ini读取内容至dora2
dora2.output(cout);
return 0;
}上述代码的执行结果为:
No. Name Age
-------------------------------
20210426 Dora Chen 17
-------------------------------
C++ 97
Calculus 70
Economics 65C++的标准模板库并不提供解析ini文件的能力,本着“不要重新发明轮子”的原则,我们引用了大名鼎鼎的boost库才完成相应任务。
??首先作者下载了当前最新版本(v1.78.0)的boost库压缩包并将其解压缩至D:/C2Cpp目录下,如图20-6所示。
接下来,作者在Qt Creator中编辑了项目文件StudentInfo.pro,增加了下述内容中的第6行。该行内容将boost库目录纳入项目的头文件包含目录中。这样,当cpp文件通过#include宏指令引入boost中的头文件时,编译器里的预处理器可以在相应的目录中找到它们。
??注意:在Qt Creator中创建项目时,其中的Build System项有cmake和qmake两种,请务必选择qmake,否则会找不到下述StudentInfo.pro文件。
TEMPLATE = app
CONFIG += console c++11
CONFIG -= app_bundle
CONFIG -= qt
INCLUDEPATH += D:/C2Cpp/boost_1_78_0
SOURCES += \
main.cpp第5 ~ 6行:引入boost库中的属性树(ptree)以及ini解析器(ini_parser)头文件。属性树是一种树形数据结构,对其内部工作原理的探讨超出来本书的范围,在本书中,我们将其视为提供了可用功能接口的黑盒,而忽视其内部结构。
第80 ~ 91行:程序主体部分。main()首先构造了一个名为dora1的Student对象,随后的三行通过addScore()成员函数为dora1添加了C++、微积分、经济学三门课程的成绩。接下来,执行dora1的save()函数将对象内容序列化并存储至ini格式的文件dora.ini。然后,程序创建了一个新的Student对象dora2,通过执行dora2的load()函数从dora.ini读取数据至dora2,最后通过dora2的output()函数将信息打印至屏幕,以便确认dora2与dora1在内容上的一致性。
本程序中Score、Student类型的数据成员声明、构造函数定义等部分并无特别之处,我们重点解释Student类型的save()和load()函数。
35 void save(const string& sFile){
36 boost::property_tree::ptree s;
37
38 s.put("basic.sNo",sNo);
39 s.put("basic.sName",sName);
40 s.put("basic.iAge",iAge);
41
42 s.put("scores.size",scores.size());
43 for (unsigned int i=0;i<scores.size();i++){
44 auto& r = scores[i];
45 s.put(string("scores.sName_")+std::to_string(i),r.sName);
46 s.put(string("scores.iScore_")+std::to_string(i),r.iScore);
47 }
48
49 boost::property_tree::ini_parser::write_ini(sFile,s);
50 }第35 ~ 50行:Student的save()函数负责将Student对象内容序列化并存储至ini格式文件sFile中,sFile为指定文件名。
第36行:函数构造了一个空的属性树(ptree)对象s,类型ptree位于boost::property_tree名字空间之下。
第38 ~ 40行:接下来,通过s的put函数往属性树中添加键值对。如第38行所示,put()函数的第一个参数为键,第二个参数为值,其中键以S.K的形式提供,S表示分区(Section),K表示分区下的健。具体到本例,s.put(“basic.sNo”,sNo)的执行结果对应dora.ini中的下述内容:
[basic]
sNo=20210426读者应注意到,属性树的put()函数是函数名重载的,因为其第2个参数既可以是字符串,也可以是整数或者其他类型的对象。
第42行:在scores分区下添加名为size的键,表示scores向量的元素数量。具体到本例,执行结果对应dora.ini中的下述内容:
[scores]
size=3第43 ~ 47行:对scores向量进行遍历,将课程名称和分数逐一加入属性树s。为了区分不同序号的课程,在键名后附加整数序号。具体到本例,执行结果对应dora.ini中的下述内容:
[scores]
...
sName_0=C++
iScore_0=97
sName_1=Calculus
iScore_1=70
sName_2=Economics
iScore_2=65第49行:通过boost::property_tree::ini_parser名字空间下的write_ini()函数将属性树s中的信息写入文件sFile,文件格式为ini。
第52 ~ 67行:Student的load()函数负责从ini格式文件sFile读取内容并填入内部数据结构,其中,sFile为指定文件名。
第54行:使用boost::property_tree::ini_parser名字空间下的read_ini()函数将指定的ini格式文件sFile的全部内容读入属性树s。
第56 ~ 66行:通过get()函数从属性树s获取属性并填入内部数据结构。属性树的get()函数用于读取其内部的键值对。函数的第一个参数为形如S.K的键,S表示分区(Section),K表示分区下的健。第二个参数则为默认值,即当指定的键不存在时,直接返回默认值。
容易看出,同put()函数一样,get()函数也有多个函数名重载的版本,其第2个参数(默认值)的类型间接决定了get()函数的返回值类型。
除ini格式之外,boost库还支持对xml、json等结构化文本文件的读取。作者的建议是,对于那些结构化的数据,尽量使用现成的结构化的文本文件格式来存取。除boost外,大部分第三方C++库,比如Qt,也提供对ini等结构化文本文件的直接支持,没有必要设计“个性化”的文本文件存储结构。
练习巩固 |
20-3(json文件)修改20.3节中的示例程序,使用json格式存储学生及成绩信息。 |
本案例节选自作者编写的教材及配套实验指导书。
《C++编程基础及应用》(高等教育出版社,出版过程中)
《Python编程基础及应用》,高等教育出版社
《Python编程基础及应用实验教程》,高等教育出版社
高校教师同行如果期望索取样书,教学支持资料,加群,请私信作者,联系时请提供学校及个人姓名为盼,各高校在读学生勿扰为谢。
青少年读者们如果期望系统性地学习Python及C/C++程序设计语言,欢迎尝试下述今日头条(西瓜)免费视频课程。
相关推荐
- 怎么ghost电脑系统(怎样ghost)
-
使用GHOST软件备份系统即可。1、网上下载一键GOST安装好,重启电脑运行一键gost-选择手动进入GOST。2、进入GHOST的操作界面,点OK。3、选择菜单到Local(本机)--Partiti...
- u盘读取软件下载(u盘读取器下载)
-
手机播放U盘里的视频不用刻意的去安装什么播放器,一般手机里自带的播放器就能够直接播放U盘里的一般常见的视频。只要你要播放的视频,都是平时在电脑上或者电视上能够正常播放的视频,一般在手机里面它的系统自带...
- office2020安装包百度云下载
-
Office2020和Office2019是微软的办公套件产品,两个版本之间有以下区别:1.发布时间:Office2020于2021年10月发布,而Office2019于2018年9月发布。...
- 硬盘恢复分区(硬盘恢复分区怎么删除)
-
1、在电脑上下载DiskGenius软件。2、双击运行该软件,软件会自动识别硬盘。当软件自动识别硬盘之后,右键单击硬盘的盘符,出现下拉菜单栏,选择搜索已丢失分区(重建分区表)选项。3、右键单击硬盘盘符...
-
- edge 浏览器(edge浏览器官网下载)
-
目前没有,如果是平板安装了WIN10是会内置MicrosoftEdge浏览器的。edge是由微软开发的基于Chromium开源项目及其他开源软件的网页浏览器。Edge浏览器主要特点是能够支持目前主流的Web技术,作为Windows10自带...
-
2025-11-18 06:51 off999
-
- 网易163邮箱免费注册(163网易免费邮件注册)
-
163邮箱登录入口页面官方地址:https://mail.163.com/163邮箱登录注册方法1、进入邮箱登入首页,我们点击右下角“去注册”按钮,进入注册界面;2、这里直接填写账号和密码内容,点一下同意那里呈蓝色圆点;再点下一步。3、再填...
-
2025-11-18 06:03 off999
- 苹果商城app下载安装(苹果商店app免费下载)
-
一、苹果手机下载软件显示APP内购买的意思是APP可以免费下载使用,但是该APP内有付费内容,也就是通常所说的收费道具。二、不是所有应用都会提供App内购买项目。如果某个应用提供App内购买...
- 惠普电脑中国官网(惠普手提电脑官网)
-
https://support.hp.com/cn是惠普笔记本售后服务官网。惠普维修服务中心通过整合线上线下相关资源,向国内用户提供方便快捷、安全可靠的优质电子产品维修服务。目前拥有北京6家、全国30...
- windows2003密钥序列号(win2003 密钥)
-
没有密钥就无法完成程序安装。使用或者购买密钥才能安装
- 电脑产品密钥在哪里找win10(电脑产品密钥在哪里找新机)
-
要查看电脑上Windows10的产品密钥,你可以按照以下步骤进行操作:打开“开始”菜单,然后点击“设置”图标(齿轮状图标)。在“设置”窗口中,点击“更新和安全”选项。在左侧导航栏中,选择“激活”选项...
- 电脑有网络但上不到网(电脑有网但是上不了网)
-
如果电脑显示有网但无法上网,可能是网络连接出现问题。这种情况可能是由于以下几个原因导致的:1.路由器或者调制解调器出现故障;2.电脑的网络设置有误;3.网络供应商的服务中断或者限制了你的网络访问...
- 笔记本突然开不了机了是什么情况
-
1.检查笔记本是否有电,当内置电池用完而又没有充电的情况下,会导致笔记本无法开机,插上电源充电即可。2.内置电池损坏维修更换即可。3.开机时按F8,在高级选项中选择最后一次正确的配置即可。4.中病毒可...
- windows11办公软件(windows11的office)
-
1、首先点击电脑底部的Windows图标2、进入开始页面点击office套件中的任意应用,如Word3、页面弹出登录按钮,和创建按钮,如已有账号,点击登录4、接着进入激活office页面,输入offi...
-
- 7z文件怎么打开(7z文件改什么后缀才能打开)
-
7z是一种压缩格式,和我们在Windows平台上看到的rar类似;7z原本是7-zip开源的压缩文件所支持的压缩格式,目前大多数压缩软件也支持打开,如若安装了第三方压缩软件双击即可打开7z。7z文件的打开方式介绍如下: 1、扩展名为...
-
2025-11-18 02:03 off999
- 重装系统后连不上网(重装系统后无法连网)
-
1、首先,在安装系统完成之后,界面右下角网络连接显示不可用?我们需要通过,系统本身自带的诊断系统进行诊断,以避免是否是物理原因造成的网络不能正常链接。2、其次,检测结果如果是显示的未能安装网络适配器,...
欢迎 你 发表评论:
- 一周热门
-
-
抖音上好看的小姐姐,Python给你都下载了
-
全网最简单易懂!495页Python漫画教程,高清PDF版免费下载
-
Python 3.14 的 UUIDv6/v7/v8 上新,别再用 uuid4 () 啦!
-
python入门到脱坑 输入与输出—str()函数
-
飞牛NAS部署TVGate Docker项目,实现内网一键转发、代理、jx
-
宝塔面板如何添加免费waf防火墙?(宝塔面板开启https)
-
Python三目运算基础与进阶_python三目运算符判断三个变量
-
(新版)Python 分布式爬虫与 JS 逆向进阶实战吾爱分享
-
慕ke 前端工程师2024「完整」
-
失业程序员复习python笔记——条件与循环
-
- 最近发表
- 标签列表
-
- python计时 (73)
- python安装路径 (56)
- python类型转换 (93)
- python进度条 (67)
- python吧 (67)
- python的for循环 (65)
- python格式化字符串 (61)
- python静态方法 (57)
- python列表切片 (59)
- python面向对象编程 (60)
- python 代码加密 (65)
- python串口编程 (77)
- python封装 (57)
- python写入txt (66)
- python读取文件夹下所有文件 (59)
- python操作mysql数据库 (66)
- python获取列表的长度 (64)
- python接口 (63)
- python调用函数 (57)
- python多态 (60)
- python匿名函数 (59)
- python打印九九乘法表 (65)
- python赋值 (62)
- python异常 (69)
- python元祖 (57)
