当前位置: 首页 > article >正文

踩坑记:Poco库,MySql,解析大文本的bug

这两天在调试一个小功能,使用c++,读取MySql。使用的是Poco库。按照官网的写法:

    std::cout << "read normal data by poco recordset "<<std::endl;
	Poco::Data::MySQL::Connector::registerConnector();
	Poco::Data::Session session("MySQL", "host=127.0.0.1;port=3306;user=root;password=Citic@123;db=test");
	Poco::Data::Statement select(session);
	select << "select id,name from student ",now;//查询
	Poco::Data::RecordSet rs(select);//创建结果集
	bool more = rs.moveFirst();//第一条
	while (more)
	{
		int id = rs[0].convert<int>();//读取id
		std::string name = rs[1].convert<std::string>();//读取name
		std::cout << "id=" << id << " name=" << name << std::endl;//输出
		more = rs.moveNext();//下一条
	}

 代码没有问题,可以查询到数据,并输出:

换一张表,其中有一个字段是text,里面存储的数据比较大,4K个字符。结果就报错了。表结构如下:

查询代码:

	std::cout << "read normal data by poco recordset " << std::endl;
	Poco::Data::MySQL::Connector::registerConnector();
	Poco::Data::Session session("MySQL", "host=127.0.0.1;port=3306;user=root;password=Citic@123;db=test");
	Poco::Data::Statement select(session);
	select << "select uid,data1 from test ", now;
	Poco::Data::RecordSet rs(select);
	bool more = rs.moveFirst();
	while (more)
	{
		int id = rs[0].convert<int>();//读取id
		std::string data = rs[1].convert<std::string>();//读取data
		std::cout << "id=" << id << " data=" << data << std::endl;//输出
		more = rs.moveNext();//下一条
	}

两次代码一模一样,但是执行就报错了:

报错:ucrtbase.dll,处有未经处理的异常: 将一个无效参数传递给了将无效参数视为严重错误的函数。
这个dll属于系统C语言运行时。在网上搜相关的内容,基本上都是流读写或者关闭不正常导致。经在尝试各种方法以后,还是无法解决这个问题。

推测,应该是poco库本身在对mysql的大文本字段进行解析的时候,出bug了。只好另辟蹊径。偶然发现,RecordSet这个类,有一个copy(ostrem),大致意思是直接给recordset流拷贝一下。既然这样,那么就来尝试一下。

    std::cout << "read big data by ofstream" << std::endl;
	Poco::Data::MySQL::Connector::registerConnector();
	Poco::Data::Session session("MySQL", "host=127.0.0.1;port=3306;user=root;password=Citic@123;db=test");
	Poco::Data::Statement select(session);
	select << "select uid,data1 from test ", now;
	Poco::Data::RecordSet rs(select);//创建数据集,select对象给数据全部写入数据集
	std::ofstream outFile("data.txt");//创建一个文件流
	rs.copy(outFile);//流拷贝
	outFile.flush();//强制写入

这个代码的意思,创建一个文件流,输出到test.txt。然后直接从recordset把流拷贝走。如果成功的话,这个文件里面应该是mysql查询到的数据。

执行结果如上图所示。实际上,这就是mysql返回的查询结果,rescordset里面存储的就是这个。recordset再提供一些方法去从这个数据里面解析成一个个值。到此基本上发现了问题,就是Poco自带的解析方法,再解析大量数据的时候,出问题了。

所以:不想重新编译Poco库,那就想办法自己解析。解析办法,就是按字符串,一行一行去解析。代母如下:

	std::cout << "read big data by ostream" << std::endl;
	Poco::Data::MySQL::Connector::registerConnector();
	Poco::Data::Session session("MySQL", "host=127.0.0.1;port=3306;user=root;password=Citic@123;db=test");
	Poco::Data::Statement select(session);
	select << "select uid,data1 from test ", now;
	Poco::Data::RecordSet rs(select);//创建数据集,select对象给数据全部写入数据集
	std::stringstream  stm;//定义一个用于接收recoredset的字符串流
	rs.copy(stm);//结果集复制到字符串流
	stm.flush();//强制读取完毕
	char line[4500] = { 0 };//读取字符串流读取的缓存,要大于一行总字节长度
	stm.getline(line, 4500);//跳过标题 uid   ,  data1
	stm.getline(line, 4500);//跳过分割 --------------------
	int id = 0;//id变量
	std::string data = "";//data变量
	while (stm.getline(line, 4500))
	{
		sscanf(line, "%d ", &id);//解析id
		data = std::string(line + 17);//解析长文本
		std::cout << id << "-----" << data << std::endl;
	}

 

运行结果,解析成功,并且不报错。

解析原理就是把recordset里面的流先复制到字符串流,然后再一行一行的读取。前两行是标题和分隔符,后面是数据,按照自己定义的数据规则去读取。

line+17:因为uid是一个int,读取出来,占了16个字节,前面留空。uid和data1列之间有一个空格,所以,data1数据开始的下标是17。

到此问题解决。


http://www.kler.cn/news/303470.html

相关文章:

  • 递归、排序、二分查找(C语言实现)
  • mybatis与concat实现模糊查询、mybatis中模糊查询concat传入参数为空时的解决方法
  • nacos安装使用调优及面试题分享
  • Apple发布会都有哪些亮点?如何在苹果手机和电脑上录制屏幕?
  • MATLAB默认工作路径修改
  • 串口通信数据包介绍和包结构定义实例
  • 【Echarts】vue3打开echarts的正确方式
  • real, dimension(3) :: rho1 和 real :: rho1(3) 的区别
  • C++学习笔记----7、使用类与对象获得高性能(一)---- 书写类(1)
  • element表格合并列数据相同合并单元格
  • 【Flutter 面试题】 无需上下文进行路由跳转原理是怎么样的
  • Python用MarkovRNN马尔可夫递归神经网络建模序列数据t-SNE可视化研究
  • 医疗报销|基于springboot的医疗报销系统设计与实现(附项目源码+论文+数据库)
  • RocketMQ 集群搭建详细指南
  • F12抓包10:UI自动化 - Elements(元素)定位页面元素
  • 【devops】devops-git之git分支与标签使用
  • Kubernetes 容器与镜像管理
  • 五、Django 路由配置
  • 如何编写ChatGPT提示词
  • LabVIEW中EPICS客户端/服务端的测试
  • 数据库系统概论(3,4)
  • 【网络安全】漏洞挖掘之会话管理缺陷
  • Layout 布局组件快速搭建
  • 如何建设数据中台(五)——数据汇集—打破企业数据孤岛
  • Android 12.0 Launcher修改density禁止布局改变功能实现
  • 【C++题解】1398. 奇偶统计
  • Apple Watch Series 10 鈦強勁
  • Swift语言基础教程、Swift练手小项目、Swift知识点实例化学习
  • IT从业者如何提升自身竞争力,应对全球化挑战。
  • Django笔记一:搭建Django环境与URL路径访问