C++ 二进制图片的读取和blob插入mysql_stmt_init—新年第一课

关于二进制图片的读取和BLOB插入一共包含五步

第一步:初始化

MYSQL_STMT* stmt = mysql_stmt_init(&mysql);

第二步:预处理sql语句

mysql_stmt_prepare(stmt,sql,sqllen);

第三步:绑定字段

mysql_stmt_bind_param(stmt,bind);

第四步:执行

mysql_stmt_excute(stmt);

第五步:关闭

mysql_stmt_close(stmt);

详细步骤如下:

1、连接数据库;这个就不详细讲解了

const char* host = "127.0.0.1";
	const char* user = "root";
	const char* password = "************";
	const char* database = "database_test";
	int port = 3306;

	MYSQL mysql;
	mysql_init(&mysql);
	mysql_library_init(0, NULL, NULL);
	//防止乱码
	mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, "GBK");

	//支持多条sql语句 CLIENT_MULTI_STATEMENTS   clientflag  默认是不支持的
	//if (!mysql_real_connect(&mysql, host, user, password, database, port, 0, 0))
	if (!mysql_real_connect(&mysql, host, user, password, database, port, NULL, 0))
	{
		cout << "failed to connect" << host << mysql_error(&mysql) << endl;
	}

	else
	{
		cout << "successfully connected " << host <<endl;
	}

2、创建数据表t_data; 创建好存放二进制数据的表 t_data

注意***:这里的数据类型,必须是blob其他和以前一样

//创建号存放二进制数据的表 t_data
	string sql = "";
	sql="CREATE TABLe IF NOT EXISTS `t_data`(\
		`id` int AUTO_INCREMENT,\
		`name` varchar(1024),\
		`data` blob,\
		`size` int,\
		PRIMARY KEY(id)\
		)";
	
	int re = mysql_query(&mysql, sql.c_str());
	if (re != 0)
	{
		cout << "failed mysql_error" << mysql_error(&mysql) << endl;
	}

3、初始化stmt

MYSQL_STMT*stmt=mysql_stmt_init(&mysql);

4、预处理sql语句

// 注意这里的插入必须是???
sql="insert into t_data (name,data,size) values (?,?,?)";

//错误输出是mysql_stmt_error(stmt);和之前不一样哦;

//sql语句,插入数据
// 注意这里的插入必须是???

	sql = "insert into `t_data` (name,data,size) values (?,?,?)";
	if (mysql_stmt_prepare(stmt, sql.c_str(), sql.size()))
	{
		cerr << "mysql_stmt_prepare failed!" << mysql_stmt_error(stmt) << endl;
	}

5、绑定字段

MYSQL_BIND bind[3]={ 0 };

//第一个数据name
bind[0].buffer_type = MYSQL_TYPE_STRING; //name文件名
bind[0].buffer = (char*)filename.c_str();//原图的文件名
bind[0].buffer_length = filename.size();
//(char*) buffer要求的是void*,而c_str()是只读的,所以要转换char*。
//而bind是可以输入可以输出,所以不可以只读。默认const是只读的,但是在这儿是插入数据,不会修改数据,可以用char*

bind[1].buffer_type = MYSQL_TYPE_BLOB;// data 文件二进制内容
bind[1].buffer = data; //二进制文件
bind[1].buffer_length = filesize; //文件大小

//把文件大小存下来
//从mysql取出来,可以知道文件大小,但是不一定将它取出来,
//经常做显示文件列表,有时候不需要显示二进制。希望有个字段将文件大小存下来

bind[2].buffer_type = MYSQL_TYPE_LONG;//长整型,不用直到size,因为是固定大小
bind[2].buffer = &filesize;  //存放指针

5.1、如何filename 和data?

在上述代码的前面需要定义filename和data大小;

//4、打开并读取文件
	string filename = "mysql.jpg";

	//打开文件可以有多种方式,可以用c的file fopen,但是这个在vs2017里面说不安全,得设置不安全选项
	//fopen_s 是多线程安全版本的,到了linux又不行了
	//为了跨平台,用C++方式读取 fstream

	//需要知道文件大小和文件二进制  考虑到空间的分配和释放 动态空间
	//int filesize = 0;
	//ios::binary必须写,因为是二进制文件,如果是文本文件,无所谓不用加,但是还是加着
	fstream in(filename, ios::in | ios::binary);
	//文件是否存在
	if (!in.is_open())
	{
		cerr << "file" << filename << "open failed" << endl;
	}
	//fopen
	//句柄,文件指针移到结尾处
	//从结尾往前移动,移动0个位置,也就是结尾
	//判断位置
	in.seekg(0, ios::end);
	// 得到文件大小,
	//文件大小和文件二进制
	int filesize = in.tellg();
	//得到大小之后,将文件移到开头,要不然待会读文件就读不到了
	in.seekg(0, ios::beg);
	//分配空间大小
	char* data = new char[filesize];
	//查看是否读完,不保证一次读完,所以用循环读,可以直到读取了多少
	int readed = 0;//已经读了多少
	while (!in.eof())
	{
		//in.read(data, filesize); data读什么数据,filesize读多少
		//指针要进行移位
		in.read(data + readed, filesize - readed);
		//上次读了多少字节
		if (in.gcount()<=0)
		{
			break;
		}
		readed += in.gcount();
	}
	in.close();

6、绑定 mysql_stmt_bind_param(stmt, bind)


	//6、绑定
	if (mysql_stmt_bind_param(stmt, bind)!=0) //定义和文档不一致,=表示成功
	{
		//cerr错误输出,在重定向的时候,可以分割开来,也可以写到文件当中
		//cout 标准输出
		/*
		cout:写到标准输出的ostream对象;
		cerr:输出到标准错误的ostream对象,常用于程序错误信息;
		clog:也是输出标准错误流(这点儿和cerr是一样的),貌似平时很少用到这个啊;
		*/
		cerr << "mysql_stmt_bind_param failed" << mysql_stmt_error(stmt) << endl;
	}

7、执行stmt sql

//7、执行stmt sql
	if (mysql_stmt_execute(stmt) != 0)
	{
		//cerr错误输出
		cerr << "mysql_stmt_execute failed" << mysql_stmt_error(stmt) << endl;
	}

8、关闭stmt

mysql_stmt_close(stmt);

9、注意****

9.1、刚才申请了data空间是动态控件,必须要释放

delete []data;

9.2、在读取文件之后,一定要把文件关闭

in.close();

完整代码如下:

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<stdio.h>
#include<mysql.h>
#include<thread>
#include<map>
#include<sstream>
#include<fstream>
//计时
#include<chrono>
using namespace std;
using namespace chrono;


int main()
{
	const char* host = "127.0.0.1";
	const char* user = "root";
	const char* password = "*********"; //输入自己数据库的密码
	const char* database = "database_test";
	int port = 3306;

	MYSQL mysql;
	mysql_init(&mysql);
	mysql_library_init(0, NULL, NULL);
	//防止乱码
	mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, "GBK");

	//支持多条sql语句 CLIENT_MULTI_STATEMENTS   clientflag  默认是不支持的
	//if (!mysql_real_connect(&mysql, host, user, password, database, port, 0, 0))
	if (!mysql_real_connect(&mysql, host, user, password, database, port, NULL, 0))
	{
		cout << "failed to connect" << host << mysql_error(&mysql) << endl;
	}

	else
	{
		cout << "successfully connected " << host <<endl;
	}
	
	//blob  blob存放二进制
	// int 最大值大概是2g
	

	//1、创建号存放二进制数据的表 t_data
	string sql = "";
	sql="CREATE TABLe IF NOT EXISTS `t_data`(\
		`id` int AUTO_INCREMENT,\
		`name` varchar(1024),\
		`data` blob,\
		`size` int,\
		PRIMARY KEY(id)\
		)";
	
	int re = mysql_query(&mysql, sql.c_str());
	if (re != 0)
	{
		cout << "failed mysql_error" << mysql_error(&mysql) << endl;
	}

	//2、初始化
	MYSQL_STMT* stmt = mysql_stmt_init(&mysql);


	//3、预处理sql语句
	sql = "insert into `t_data` (name,data,size) values (?,?,?)";
	if (mysql_stmt_prepare(stmt, sql.c_str(), sql.size()))
	{
		cerr << "mysql_stmt_prepare failed!" << mysql_stmt_error(stmt) << endl;
	}

	//4、打开并读取文件
	string filename = "mysql.jpg";

	//打开文件可以有多种方式,可以用c的file fopen,但是这个在vs2017里面说不安全,得设置不安全选项
	//fopen_s 是多线程安全版本的,到了linux又不行了
	//为了跨平台,用C++方式读取 fstream

	//需要知道文件大小和文件二进制  考虑到空间的分配和释放 动态空间
	//int filesize = 0;
	//ios::binary必须写,因为是二进制文件,如果是文本文件,无所谓不用加,但是还是加着
	fstream in(filename, ios::in | ios::binary);
	//文件是否存在
	if (!in.is_open())
	{
		cerr << "file" << filename << "open failed" << endl;
	}
	//fopen
	//句柄,文件指针移到结尾处
	//从结尾往前移动,移动0个位置,也就是结尾
	//判断位置
	in.seekg(0, ios::end);
	// 得到文件大小,
	//文件大小和文件二进制
	int filesize = in.tellg();
	//得到大小之后,将文件移到开头,要不然待会读文件就读不到了
	in.seekg(0, ios::beg);
	//分配空间大小
	char* data = new char[filesize];
	//查看是否读完,不保证一次读完,所以用循环读,可以直到读取了多少
	int readed = 0;//已经读了多少
	while (!in.eof())
	{
		//in.read(data, filesize); data读什么数据,filesize读多少
		//指针要进行移位
		in.read(data + readed, filesize - readed);
		//上次读了多少字节
		if (in.gcount()<=0)
		{
			break;
		}
		readed += in.gcount();
	}
	in.close();


	//5、绑定字段
	MYSQL_BIND bind[3] = { 0 };
	bind[0].buffer_type = MYSQL_TYPE_STRING; //name文件名
	//(char*) buffer要求的是void*,而c_str()是只读的,所以要转换char*。
	//而bind是可以输入可以输出,所以不可以只读。默认const是只读的,但是在这儿是插入数据,不会修改数据,可以用char*
	bind[0].buffer = (char*)filename.c_str();//原图的文件名
	bind[0].buffer_length = filename.size();

	bind[1].buffer_type = MYSQL_TYPE_BLOB;// data 文件二进制内容
	bind[1].buffer = data; //二进制文件
	bind[1].buffer_length = filesize; //文件大小

	//把文件大小存下来
	//从mysql取出来,可以知道文件大小,但是不一定将它取出来,
	//经常做显示文件列表,有时候不需要显示二进制。希望有个字段将文件大小存下来
	bind[2].buffer_type = MYSQL_TYPE_LONG;//长整型,不用直到size,因为是固定大小
	bind[2].buffer = &filesize;  //存放指针

	//6、绑定
	if (mysql_stmt_bind_param(stmt, bind)!=0) //定义和文档不一致,=表示成功
	{
		//cerr错误输出,在重定向的时候,可以分割开来,也可以写到文件当中
		//cout 标准输出
		/*
		cout:写到标准输出的ostream对象;
		cerr:输出到标准错误的ostream对象,常用于程序错误信息;
		clog:也是输出标准错误流(这点儿和cerr是一样的),貌似平时很少用到这个啊;
		*/
		cerr << "mysql_stmt_bind_param failed" << mysql_stmt_error(stmt) << endl;
	}

	//7、执行stmt sql
	if (mysql_stmt_execute(stmt) != 0)
	{
		//cerr错误输出
		cerr << "mysql_stmt_execute failed" << mysql_stmt_error(stmt) << endl;
	}
	delete [] data;
	mysql_stmt_close(stmt);

	mysql_close(&mysql);
	mysql_library_end();
	system("pause");
	return 0;
}

插入成功

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/286707.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JVM虚拟机:各种JVM报错总结

错误 java.lang.StackOverflowError java.lang.OutOfMemoryError:java heap space java.lang.OutOfMemoryError:GC overhead limit exceeded java.lang.OutOfMemoryError:Direct buffer memory java.lang.OutOfMemoryError:unable to create new native thread java.lang.OutOf…

WPF容器的背景对鼠标事件的影响

背景&#xff1a;在实现鼠标拖动窗口的过程中发现对父容器设置了鼠标拖动窗口的事件MouseLeftButtonDown private void DragWindow(object sender, MouseButtonEventArgs e) {if (e.LeftButton MouseButtonState.Pressed)DragMove(); } 问题&#xff1a;非常困惑的是&#x…

python慕课版课后题答案,python慕课作业答案

这篇文章主要介绍了中国大学慕课python测验答案&#xff0c;具有一定借鉴价值&#xff0c;需要的朋友可以参考下。希望大家阅读完这篇文章后大有收获&#xff0c;下面让小编带着大家一起了解一下。 Flag 8月29日前学习完MOOC_Python课程&#xff0c;以下各测试题均来自于Python…

Rockchip平台Android应用预安装功能(基于Android13)

Rockchip平台Android应用预安装功能(基于Android13) 1. 预安装应用类型 Android上的应用预安装功能&#xff0c;主要是指配置产品时&#xff0c;根据厂商要求&#xff0c;将事先准备好的第三方应用预置进Android系统。预安装分为以下几种类型&#xff1a; 安装不可卸载应用安…

Axure医疗-住院板块,住院患者原型预览,新增医护人员原型预览,新增病房原型预览,选择床位原型预览,主治医生原型预览,主治医生医嘱原型预览

目录 一.医疗项目原型图-----住院板块 1.1 住院板块原型预览 1.2 新增住院患者原型预览 1.3 新增医护人员原型预览 1.4 新增病房原型预览 1.5 选择床位原型预览 1.6 主治医生原型预览 1.7 主治医生医嘱原型预览 1.8 主治医生查看患者报告原型预览 1.9 护士原型预…

008、所有权

所有权可以说是Rust中最为独特的一个功能了。正是所有权概念和相关工具的引入&#xff0c;Rust才能够在没有垃圾回收机制的前提下保障内存安全。 因此&#xff0c;正确地了解所有权概念及其在Rust中的实现方式&#xff0c;对于所有Rust开发者来讲都是十分重要的。在本文中&…

「Vue3面试系列」Vue3 所采用的 Composition Api 与 Vue2 使用的 Options Api 有什么不同?

文章目录 开始之前正文一、Options Api二、Composition Api三、对比逻辑组织Options APICompostion API 逻辑复用 小结 开始之前 Composition API 可以说是Vue3的最大特点&#xff0c;那么为什么要推出Composition Api&#xff0c;解决了什么问题&#xff1f; 通常使用Vue2开…

Model::unguard()的作用

这是在生成假数据时碰见的&#xff0c;浅查了一下 Model::unguard() 是 Laravel 框架中的一个方法&#xff0c;它的作用是取消对 Eloquent 模型的属性赋值的安全性保护。 在默认情况下&#xff0c;Laravel 的 Eloquent 模型会对属性赋值做一些安全性检查&#xff0c;例如防止…

Vue Cli inspect

Vue Cli inspect vue-cli-service inspect&#xff1a;可以使用 vue-cli-service inspect 来审查一个 Vue CLI 项目的 webpack config 使用方法&#xff1a; 1、输出在控制台&#xff1a;vue-cli-service inspect 2、输在在文件中&#xff1a;vue-cli-service inspect -->…

频谱论文:空间频率插值的无线电地图 Space-Frequency-Interpolated Radio Map

#频谱# K. Sato, K. Suto, K. Inage, K. Adachi and T. Fujii, "Space-Frequency-Interpolated Radio Map," in IEEE Transactions on Vehicular Technology, vol. 70, no. 1, pp. 714-725, Jan. 2021, doi: 10.1109/TVT.2021.3049894. 东京理科大学&#xff0…

Flink实时电商数仓(十)

common模块回顾 app BaseApp: 作为其他子模块中使用Flink - StreamAPI的父类&#xff0c;实现了StreamAPI中的通用逻辑&#xff0c;在其他子模块中只需编写关于数据处理的核心逻辑。BaseSQLApp: 作为其他子模块中使用Flink- SQLAPI的父类。在里面设置了使用SQL API的环境、并行…

桌面天气预报软件 Weather Widget free mac特点介绍

Weather Widget free for Mac多种吸引人的小部件设计可供选择&#xff0c;可以随时了解天气&#xff01;还可以在Dock和菜单栏中为您提供简短的天气预报或当前状况的概述。 Weather Widget free for Mac软件介绍 始终在桌面上使用时尚的天气小部件来随时了解天气&#xff01;多…

jenkins +jmeter 报告乱码解决

问题&#xff1a;生产报告会乱码的问题&#xff0c;一般是有编码格式引起的。我遇到的问题是&#xff0c;jmeter需要读取csv的数据作为参数。但是我们并不知道csv保存是什么编码格式&#xff0c;有可能不是utf-8的编码格式&#xff0c;所以会导致中文乱码的问题 解决方案&#…

安装Unity详细教程(如何获取免费个人版许可证)

文章目录 下载Unity Hub安装Unity Hub登录获取免费个人版许可证安装Unity编辑器卸载Unity编辑器 下载Unity Hub 首先&#xff0c;我们需要到Unity的官网下载Unity Hub&#xff1a;Unity CN 我们可以在Unity Hub上管理我们的编辑器版本和项目文件。 安装Unity Hub 然后安装Un…

kubeadm创建k8s集群

kubeadm来快速的搭建一个k8s集群&#xff1a; 二进制搭建适合大集群&#xff0c;50台以上。 kubeadm更适合中下企业的业务集群。 部署框架 master192.168.10.10dockerkubelet kubeadm kubectl flannelnode1192.168.10.20dockerkubelet kubeadm kubectl flannelnode2192.168.1…

selenium实现UI自动化

1.selenium简介 selenium是支持web浏览器自动化的一系列工具和库的综合项目。具有支持linux、windows等多个平台&#xff0c;支持Firefox、chrome等多种主流浏览器&#xff1b;支持Java、Python等多种语言。 主要包括的三大工具有&#xff1a; WebDriver&#xff08;rc 1.0)、…

JavaScript:作用域变量回收

JavaScript&#xff1a;作用域&变量回收 局部作用域函数作用域块作用域 全局作用域作用域链变量在浏览器模型中的位置浏览器模型全局变量的产生情况直接赋值全局对象与var全局对象的区别 垃圾回收机制引用计数法标记清除法 闭包变量提升&函数提升 作用域规定了变量能够…

k8s基础架构

k8s基础架构 创建pod流程 &#xff08;1&#xff09;用户通过kubectl向api-server发起创建pod请求&#xff1b; &#xff08;2&#xff09;apiserver通过对应的kubeconfig进行认证&#xff0c;认证通过后将yaml中的po信息存到etcd&#xff1b; &#xff08;3&#xff09;Contr…

图像分割-漫水填充法 floodFill

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 本文的C#版本请访问&#xff1a;图像分割-漫水填充法 floodFill (C#&#xff09;-CSDN博客 FloodFill方法是一种图像处理算法&#…

软件测试/测试开发丨Vuetify框架的使用

介绍 Vuetify 是一个基于 Vue.js 精心打造 UI 组件库&#xff0c;整套 UI 设计为 Material 风格。能够让没有任何设计技能的开发者创造出时尚的 Material 风格界面。 为什么要使用Vuetify框架 所有组件遵从 Material Design 设计规范&#xff0c;UI 体验非常优秀&#xff0c…