C语言实现往MySQL插入和读取图片
准备工作
客户端安装C接口库libmysqlclient:
sudo apt install libmysqlclient-dev
用到的表的结构:
CREATE TABLE TBL_USER (
U_ID INT PRIMARY KEY AUTO_INCREMENT,
U_NAME VARCHAR(32),
U_GENDER VARCHAR(8),
U_IMG BLOB
);
实现的功能与实现逻辑
在这里插入图片描述
- 从node server往数据库服务器上的某个表插入带有图片字段的记录
- 从磁盘上读出文件。
- 将读出的文件写入到MySQL服务器上。
- 从node server向数据库服务器查询某条记录中的图片字段
- 从MySQL服务器读取图片的数据到节点服务器上。
- 将读到的图片数据写到node server上的某个文件中。
代码实现
从磁盘上读出文件
这里实现的也就是第一个功能的第一步用到的函数。读取出文件写入到buffer中:首先打开文件,然后读取文件的数据写入到缓冲中,供待会发送到 MySQL服务器用
int read_image(char *filename, char *buffer)
{
if(filename == NULL || buffer == NULL)
{
return -1;
}
FILE *fp = fopen(filename, "rb");
if(fp == NULL)
{
printf("fopen failed\n");
return -2;
}
fseek(fp, 0, SEEK_END);
int length = ftell(fp);
fseek(fp, 0, SEEK_SET);
int size = fread(buffer, 1, length, fp);
if(size != length)
{
printf("fread failed:%d\n", size);
return -3;
}
fclose(fp);
return size;
}
将读到的数据写入磁盘文件
int write_image(char *filename, char *buffer, int length)
{
if(filename == NULL || buffer == NULL || length <= 0)
{
return -1;
}
FILE *fp = fopen(filename, "wb+");
if(fp == NULL)
{
printf("fopen failed\n");
return -2;
}
int size = fwrite(buffer, 1, length, fp);
if(size != length)
{
printf("fwrite failed:%d\n", size);
}
fclose(fp);
return size;
}
将buffer的内容写入到MySQL服务器上
statement的函数调用流程可参考https://dev.mysql.com/doc/c-api/5.7/en/c-api-prepared-statement-interface-usage.html
int mysql_write(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_INSERT_IMG_USER, strlen(SQL_INSERT_IMG_USER));
if(ret)
{
printf("mysql_stmt_prepare:%s\n", mysql_error(handle));
return -2;
}
MYSQL_BIND param = {0};
param.buffer_type = MYSQL_TYPE_LONG_BLOB;
param.buffer = NULL;
param.is_null = 0;
param.length = NULL;
ret = mysql_stmt_bind_param(stmt, ¶m);
if(ret)
{
printf("mysql_stmt_bind_param:%s\n", mysql_error(handle));
return -3;
}
ret = mysql_stmt_send_long_data(stmt, 0, buffer, length);
if(ret)
{
printf("mysql_stmt_send_long_data:%s\n", mysql_error(handle));
return -4;
}
ret = mysql_stmt_execute(stmt);
if(ret)
{
printf("mysql_stmt_execute:%s\n", mysql_error(handle));
return -5;
}
ret = mysql_stmt_close(stmt);
if(ret)
{
printf("mysql_stmt_close:%s\n", mysql_error(handle));
return -6;
}
return ret;
}
将MySQL查询语句传回的图片数据读取到buffer中
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;
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 -4;
}
while(1)
{
ret = mysql_stmt_fetch(stmt);
if(ret != 0 && ret != MYSQL_DATA_TRUNCATED)
break;
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_stmt_close(stmt);
return total_length;
}
未解问题:这里mysql_read读取获得结果集的每一行退出循环的条件为什么是
if(ret != 0 && ret != MYSQL_DATA_TRUNCATED)
break;
个人理解:
MYSQL_NO_DATA = 100 MYSQL_DATA_TRUNCATED = 101 ret != 0 有三种情况:错误发生, MYSQL_NO_DATA ,MYSQL_DATA_TRUNCATED 因为发送图片数据的时候是分段发的,所以遇到MYSQL_DATA_TRUNCATED 截短错误是正常的,除此之外其他错误就需要退出循环了.
主函数测试代码
printf("read image and write mysql\n");
char buffer[FILE_IMAGE_LENGTH] = {0};
int length = read_image("/home/jyhlinux/share/05_mysql/0voice.jpg", buffer);
if(length < 0) goto Exit;
mysql_write(&mysql, buffer, length);
printf("read mysql and write image\n");
memset(buffer, 0x00, FILE_IMAGE_LENGTH);
length = mysql_read(&mysql, buffer, FILE_IMAGE_LENGTH);
write_image("a.jpg", buffer, length);
源代码
#include <mysql.h>
#include <stdio.h>
#include <string.h>
#define JYH_DB_SERVER_IP "192.168.200.129"
#define JYH_DB_SERVER_PORT 3306
#define JYH_DB_SERVER_USERNAME "admin"
#define JYH_DB_SERVER_PASSWORD "123456"
#define JYH_DB_DEFAULTDB "JYH_DB"
#define SQL_INSERT_TBL_USER "INSERT TBL_USER(U_NAME, U_GENDER) VALUES('czw', 'man');"
#define SQL_SELECT_TBL_USER "SELECT * FROM TBL_USER;"
#define SQL_DELETE_TBL_USER "CALL PROC_DELETE_USER('czw')"
#define SQL_INSERT_IMG_USER "INSERT TBL_USER(U_NAME, U_GENDER, U_IMG) VALUES('ljf', 'woman', ?);"
#define SQL_SELECT_IMG_USER "SELECT U_IMG FROM TBL_USER WHERE U_NAME='ljf';"
#define FILE_IMAGE_LENGTH (64*1024)
int jyh_mysql_select(MYSQL *mysql)
{
if(mysql_real_query(mysql, SQL_SELECT_TBL_USER, strlen(SQL_SELECT_TBL_USER)))
{
printf("mysql_real_query: %s\n", mysql_error(mysql));
return -1;
}
MYSQL_RES *res = mysql_store_result(mysql);
if(NULL == res)
{
printf("mysql_store_result: %s \n", mysql_error(mysql));
return -2;
}
int num_rows = mysql_num_rows(res);
printf("rows: %d\n", num_rows);
int num_fields = mysql_num_fields(res);
printf("fields: %d\n", num_fields);
MYSQL_ROW row;
while((row = mysql_fetch_row(res)))
{
unsigned int i = 0;
for(i = 0; i < num_fields; i++)
{
printf("%s\t", row[i]);
}
printf("\n");
}
mysql_free_result(res);
return 0;
}
int read_image(char *filename, char *buffer)
{
if(filename == NULL || buffer == NULL)
{
return -1;
}
FILE *fp = fopen(filename, "rb");
if(fp == NULL)
{
printf("fopen failed\n");
return -2;
}
fseek(fp, 0, SEEK_END);
int length = ftell(fp);
fseek(fp, 0, SEEK_SET);
int size = fread(buffer, 1, length, fp);
if(size != length)
{
printf("fread failed:%d\n", size);
return -3;
}
fclose(fp);
return size;
}
int write_image(char *filename, char *buffer, int length)
{
if(filename == NULL || buffer == NULL || length <= 0)
{
return -1;
}
FILE *fp = fopen(filename, "wb+");
if(fp == NULL)
{
printf("fopen failed\n");
return -2;
}
int size = fwrite(buffer, 1, length, fp);
if(size != length)
{
printf("fwrite failed:%d\n", size);
}
fclose(fp);
return size;
}
int mysql_write(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_INSERT_IMG_USER, strlen(SQL_INSERT_IMG_USER));
if(ret)
{
printf("mysql_stmt_prepare:%s\n", mysql_error(handle));
return -2;
}
MYSQL_BIND param = {0};
param.buffer_type = MYSQL_TYPE_LONG_BLOB;
param.buffer = NULL;
param.is_null = 0;
param.length = NULL;
ret = mysql_stmt_bind_param(stmt, ¶m);
if(ret)
{
printf("mysql_stmt_bind_param:%s\n", mysql_error(handle));
return -3;
}
ret = mysql_stmt_send_long_data(stmt, 0, buffer, length);
if(ret)
{
printf("mysql_stmt_send_long_data:%s\n", mysql_error(handle));
return -4;
}
ret = mysql_stmt_execute(stmt);
if(ret)
{
printf("mysql_stmt_execute:%s\n", mysql_error(handle));
return -5;
}
ret = mysql_stmt_close(stmt);
if(ret)
{
printf("mysql_stmt_close:%s\n", mysql_error(handle));
return -6;
}
}
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;
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 -4;
}
while(1)
{
ret = mysql_stmt_fetch(stmt);
if(ret != 0 && ret != MYSQL_DATA_TRUNCATED)
break;
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_stmt_close(stmt);
return total_length;
}
int main()
{
MYSQL mysql;
if(NULL == mysql_init(&mysql))
{
printf("mysql_init:%s\n", mysql_error(&mysql));
return -1;
}
if(!mysql_real_connect(&mysql, JYH_DB_SERVER_IP, JYH_DB_SERVER_USERNAME,
JYH_DB_SERVER_PASSWORD, JYH_DB_DEFAULTDB, JYH_DB_SERVER_PORT, NULL, 0))
{
printf("mysql_real_connect:%s\n", mysql_error(&mysql));
return -2;
}
#if 1
if(mysql_real_query(&mysql, SQL_INSERT_TBL_USER,strlen(SQL_INSERT_TBL_USER)))
{
printf("mysql_real_query:%s\n", mysql_error(&mysql));
return -3;
}
#endif
printf("mysql-insert:\n");
jyh_mysql_select(&mysql);
#if 1
if(mysql_real_query(&mysql, SQL_DELETE_TBL_USER,strlen(SQL_DELETE_TBL_USER)))
{
printf("mysql_real_query:%s\n", mysql_error(&mysql));
return -3;
}
#endif
printf("mysql-delete:\n");
jyh_mysql_select(&mysql);
printf("read image and write mysql\n");
char buffer[FILE_IMAGE_LENGTH] = {0};
int length = read_image("/home/jyhlinux/share/05_mysql/0voice.jpg", buffer);
if(length < 0) goto Exit;
mysql_write(&mysql, buffer, length);
printf("read mysql and write image\n");
memset(buffer, 0x00, FILE_IMAGE_LENGTH);
length = mysql_read(&mysql, buffer, FILE_IMAGE_LENGTH);
write_image("a.jpg", buffer, length);
Exit:
mysql_close(&mysql);
return 0;
}
心得
这个代码的函数不需要死记硬背,都是官方文档有的,真正用到的时候懂得找到文档看懂文档 即可。
|