C语言使用MySQL读取BLOB字段图像数据
我们希望从表中读取用户charon的图像数据U_IMG字段并保存为文件或进行其他处理。
在项目中,我们经常需要将图像等二进制大对象(Binary Large OBject,简称 BLOB)存储到数据库中,之后再读取出来进行处理。本文将以一个完整的 C 语言 MySQL 客户端代码为例,重点讲解如何 从 MySQL 中读取 BLOB 图像数据,并附上实际的
mysql_read函数实现与剖析
一、场景概述
我们有如下数据库表结构(简化):
CREATE TABLE TBL_USER (
U_ID INT AUTO_INCREMENT PRIMARY KEY,
U_NAME VARCHAR(100),
U_GENGDER VARCHAR(10),
U_IMG LONGBLOB
);
通过 SQL 语句:
SELECT U_IMG FROM TBL_USER WHERE U_NAME = 'charon';
我们希望从表中读取用户 charon 的图像数据 U_IMG 字段并保存为文件或进行其他处理。
二、mysql_read 函数实现
int mysql_read(MYSQL *handle, char *buffer, int length) {
// 输入参数有效性检查
if (handle == NULL || buffer == NULL || length <= 0) return -1;
// 初始化预处理语句
MYSQL_STMT *stmt = mysql_stmt_init(handle);
int ret = mysql_stmt_prepare(stmt, SQL_SELECT_IMG_USER, strlen(SQL_SELECT_IMG_USER));
if (ret) {
printf("mysql_stmt_prepare : %s\n", mysql_error(handle));
return -2;
}
// 绑定结果集参数
MYSQL_BIND result = {0};
result.buffer_type = MYSQL_TYPE_LONG_BLOB; // 设置为长二进制类型
unsigned long total_length = 0; // 存储 BLOB 总长度
result.length = &total_length; // 指向长度变量的指针
// 绑定结果集
ret = mysql_stmt_bind_result(stmt, &result);
if (ret) {
printf("mysql_stmt_bind_result : %s\n", mysql_error(handle));
return -3;
}
// 执行查询
ret = mysql_stmt_execute(stmt);
if (ret) {
printf("mysql_stmt_execute : %s\n", mysql_error(handle));
return -4;
}
// 存储结果集(将结果从服务器传输到客户端)
ret = mysql_stmt_store_result(stmt);
if (ret) {
printf("mysql_stmt_store_result : %s\n", mysql_error(handle));
return -5;
}
// 循环读取 BLOB 数据(处理可能的分段情况)
while (1) {
// 读取一行数据
ret = mysql_stmt_fetch(stmt);
// 当没有更多数据或发生错误时退出循环(排除数据截断情况)
if (ret != 0 && ret != MYSQL_DATA_TRUNCATED) break;
// 逐字节读取 BLOB 数据到缓冲区
int start = 0;
while (start < (int)total_length) {
// 设置当前读取位置
result.buffer = buffer + start;
// 每次读取 1 字节
result.buffer_length = 1;
// 读取一个字节到缓冲区
mysql_stmt_fetch_column(stmt, &result, 0, start);
// 更新已读取位置
start += result.buffer_length;
}
}
// 释放预处理语句资源
mysql_stmt_close(stmt);
// 返回实际读取的字节数
return total_length;
}
三、实现细节解析
1.MYSQL_STMT 预处理语句
MYSQL_STMT *stmt = mysql_stmt_init(handle);
mysql_stmt_prepare(stmt, SQL_SELECT_IMG_USER, strlen(SQL_SELECT_IMG_USER));
使用 mysql_stmt_prepare 预编译带问号参数的 SQL(不过我们这个语句不带参数)。
2.MYSQL_BIND 结构体设置
// 绑定结果集参数
MYSQL_BIND result = {0};
result.buffer_type = MYSQL_TYPE_LONG_BLOB; // 设置为长二进制类型
unsigned long total_length = 0; // 存储 BLOB 总长度
result.length = &total_length; // 指向长度变量的指针
通过设置 buffer_type 为 MYSQL_TYPE_LONG_BLOB,告知 MySQL 我们期望获取的是大字段,同时用 result.length = &total_length; 让 MySQL 能够把实际读取到的数据长度写入 total_length 变量,方便后续处理数据长度。这是为了正确接收和处理数据库中存储的二进制数据(如图片等)。
3.执行查询并存储结果
mysql_stmt_execute(stmt);
mysql_stmt_store_result(stmt);
mysql_stmt_execute() 是告诉服务器:“把饭做好”;mysql_stmt_store_result() 是告诉服务员:“把饭打包给我”;
之后你就可以一口一口自己吃了。
store_result 会为大对象读取预分配空间。所以 mysql_stmt_store_result() 就是:
“让你一次性把服务器的数据打包拉回来”,
后面你就可以 安心地从本地 一块块读图像、读数据,不担心连不上服务器或者中途出问题。
4.分段读取 BLOB 数据
int start = 0;
while(start < (int)total_length){
result.buffer = buffer + start;
result.buffer_length = 1;
mysql_stmt_fetch_column(stmt,&result,0,&start);
start += result.buffer_length;
}
MySQL C API 对于大对象不能一次性全部加载到 buffer。你必须通过 mysql_stmt_fetch_column() 进行分段读取。
这里我们每次读取 1 字节,确保安全。你可以将 result.buffer_length 设为更大的值(如 512 或 4096)来提升性能,但需要小心避免越界。
5.返回数据长度
return total_length;
函数最终返回从数据库中读取的 BLOB 数据总字节数。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐




所有评论(0)