注意!!!
图片是否能够显示完全有一个注意点 数据表中的BLOB类型设置是否够大
1、MySQL有四种BLOB类型: ·
tinyblob:仅255个字符
blob:最大限制到65K字节
mediumblob:限制到16M字节
longblob:可达4GB
2、除了类型对后面存取文件大小有限制,还要修改mysql的配置文件。
Windows、linux基本一样通过修改文件my.ini或my.cnf文件,在文件中增加 max_allowed_packet=10M(就是最大10M,mysql默认似乎1MB,增加前先查找一下确保没有设置过)
3、做了以上设置后,如果上传较大一点文件时或者某些文件时还是出错,如报一些乱码,估计就是下面的问题了。 数据库或表的字符集问题,如hibernate连接使用utf-8,表是gbk等,一般只要设置hibernate中数据连接部分就行,如 jdbc:mysql://192.168.0.4:3306/test?useUnicode=true&characterEncoding=UTF-8
如何从磁盘中读取图片数据
//从选取的文件中读取图片数据
int ReadImg(char *filename ,char *buffer) //filename:用来存储 Path+filename buffer:用来存储
{
if (NULL == filename || buffer == NULL)
{
return -1;
}
//打开文件
FILE* fp = fopen(filename, "rb");//rb 以读的方式打开
//判断是否成功打开了文件
if (NULL == fp )
{
printf("Fopen fail! \n");
return -2;
}
//测量文件字节数(偏移量 三板斧 都得要
fseek(fp, 0, SEEK_END);将位置指针移动到文件末尾
int length = ftell(fp); // file size 确定文件的大小
fseek(fp, 0, SEEK_SET);//将位置指针移动到文件开头
int size = fread(buffer, 1,length,fp); //每次读取一个字节 从fp的指向开始 每次读1个字节 存放到buffer中 要执行length次
//判断两者长度是否一致 也就是读出来的数据大小是否等于文件大小
if (size != length)
{
printf("FileRead error!%d \n",size);
return -3;
}
//关闭文件
fclose(fp);
}
如何把数据库中的图片数据存放到文件中
//将图片数据写入磁盘
int WirteImg(char* filename, char* buffer, int length) //写到哪个文件中 写入的数据是哪些 写入的长度是多少
{
if (filename == NULL || buffer == NULL || length <= 0) return -1;
FILE* fp = fopen(filename,"wb"); //wb 以写的方式打开
//判断是否成功打开了文件
if (NULL == fp)
{
printf("Fopen fail! \n");
return -2;
}
int size = fwrite(buffer, 1, length, fp);//每次读取一个字节 从fp的指向存放 每次读1个字节 要执行length次
//判断两者长度是否一致 也就是读出来的数据大小是否等于文件大小
if (size != length)
{
printf("FileWrite error!%d \n", size);
return -3;
}
fclose(fp);
}
在表中增加一行为我们的图片存储做准备\
alter table TB_USER ADD UIMG BLOB;
MySQL写入数据
//数据库中存储图片数据
int MySQL_WriteImg(MYSQL *mysql,char *buffer, int length)
{
if (mysql == NULL || buffer == NULL || length <= 0) return -1;
MYSQL_STMT* stmt = mysql_stmt_init(mysql);//初始化数据缓存
int ret = mysql_stmt_prepare(stmt, SQL_INSERT_TB_USER_IMG, strlen(SQL_INSERT_TB_USER_IMG));
if (ret)
{
printf("mysql_stmt_prepare is error ! %s \n",mysql_error(mysql));
return -2;
}
//绑定数据
MYSQL_BIND parme = { 0 }; //用于语句输入和返回值 通常和stmt绑定使用
parme.buffer_type = MYSQL_TYPE_LONG_BLOB;
parme.buffer = NULL;
parme.is_null = 0;
parme.length = NULL;
ret = mysql_stmt_bind_param(stmt,&parme);
if (ret)
{
printf("mysql_stmt_bind_param is error ! %s \n", mysql_error(mysql));
return -3;
}
//发送数据到数据库服务器中
ret = mysql_stmt_send_long_data(stmt, 0, buffer, length);
if (ret)
{
printf("mysql_stmt_send_long_data is error ! %s \n", mysql_error(mysql));
return -4;
}
//存储到表中
ret = mysql_stmt_execute(stmt);
if (ret)
{
printf("mysql_stmt_execute is error ! %s \n", mysql_error(mysql));
return -5;
}
//以上执行完毕关闭stmt
ret = mysql_stmt_close(stmt);
if (ret)
{
printf("mysql_stmt_close is error ! %s \n", mysql_error(mysql));
return -6;
}
return ret;
}
MySQL读取数据
//从数据库中读取图片资源写入到磁盘
int MySQL_ReadImg(MYSQL *mysql,char * buffer, int length)
{
if (mysql == NULL || buffer == NULL || length <= 0) return -1;
MYSQL_STMT* stmt = mysql_stmt_init(mysql);//初始化数据缓存
//执行语句拿到返回值存储到stmt
int ret = mysql_stmt_prepare(stmt, SQL_SELECT_TB_USER_IMG, strlen(SQL_SELECT_TB_USER_IMG));
if (ret)
{
printf("mysql_stmt_prepare is error ! %s \n", mysql_error(mysql));
return -2;
}
//以下都是数据处理
//绑定结果
MYSQL_BIND result = { 0 }; //用于语句输入和返回值 通常和stmt绑定使用
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 is error ! %s \n", mysql_error(mysql));
return -3;
}
//执行语句
ret = mysql_stmt_execute(stmt);
if (ret)
{
printf("mysql_stmt_execute is error ! %s \n", mysql_error(mysql));
return -4;
}
//返回结果
ret = mysql_stmt_store_result(stmt);
if (ret) {
printf("mysql_stmt_store_result : %s\n", mysql_error(mysql));
return -5;
}
//数据显示 取出单行可以不需要外循环
while (1)
{
//mysql_stmt_fetch 抓取返回的数据集:stmt 的下一行数据
ret = mysql_stmt_fetch(stmt);
if (ret != 0 && ret != MYSQL_DATA_TRUNCATED) break; // MYSQL_DATA_TRUNCATED 出现数据截短 块存储分片 \
当mysql_stmt_fetch返回0时意味着数据读取完毕
int start = 0;
while (start<(int)total_length)
{
result.buffer = buffer + start; //result.buffer和传入的参数buffer使用的是一个内存空间
result.buffer_length = 1; //buffer_length buffer的实际大小也就是每次接受数据的最大长度
mysql_stmt_fetch_column(stmt, &result, 0, start);//mysql_stmt_fetch_column:当前行获取一列数据 s
//stmt:存储结果;
//result:保存返回数据的缓存空间;
//0:因为我们查询的数据列只有一个所以是第0个写0
//start:从什么位置开始的偏移量
start += result.buffer_length; //获取下一个偏移量 也就是当前start代表的偏移量+buffer_length的长度
}
}
//关闭stmt
mysql_stmt_close(stmt);
//返回 数据总长
return total_length;
}
本文全部代码如下:
#include <stdio.h>
#include <mysql.h>
#include <string.h>
//C U R D
//创建 更新 读取 删除
#define yang_db_server_ip "192.168.126.132" //数据库IP
#define yang_db_server_port 3306 //数据库链接的端口号
#define yang_db_server_definedb "yang_db" //该用户默认链接的数据库
#define yang_db_server_username "admin" //用户名
#define yang_db_server_password "123456" //密码
#define SQL_INSERT_TB_USER "insert TB_USER(UNAME,USEX) value('sunyu','woman');" //增加语句
#define SQL_INSERT_TB_USER_IMG "insert TB_USER(UNAME,USEX,UIMG) value('12345','woman',?);" //增加语句 在宏定义中?代表占位符因为不知道图片的内容所以使用?
#define SQL_SELECT_TB_USER "SELECT * FROM TB_USER;" //查询语句
#define SQL_SELECT_TB_USER_IMG "SELECT UIMG FROM TB_USER WHERE UNAME = '12345';" //查询语句
#define SQL_CALL_PROC_TB_USER "CALL PROC_DELETE_TBUSER('sun');" //调用删除的存储过程
#define FILE_IMAGE_LENGTH (1536*1824) //文件大小
int sel(MYSQL* sqldata)
{
//第一步
if (mysql_real_query(sqldata, SQL_SELECT_TB_USER, strlen(SQL_SELECT_TB_USER)))
{
printf("SQL_SELECT :%s \n ", mysql_error(sqldata));
}
//第二步
MYSQL_RES* res = mysql_store_result(sqldata);保存返回语句的内容
if (res == NULL)
{
printf("mysql_store_result: %s \n", mysql_error(sqldata));
return -2;
}
//第三步 判断数据集合的行数
int rows = mysql_num_rows(res);
printf("Rows :%d \n", rows);
//列数
int cows = mysql_num_fields(res);
printf("Cows :%d \n", cows);
//第四步 将返回的数据逐行取出
MYSQL_ROW row; //row是一个存放数据的数组类似于C#中的sqlread函数
while ((row = mysql_fetch_row(res))) //判断行是否为空
{
int i = 0;
for (i = 0; i < cows; i++)
{
printf("%s \t", row[i]);
}
printf("\n");
}
mysql_free_result(res);
return 0;
//goto Exit;
}
//从选取的文件中读取图片数据
int ReadImg(char *filename ,char *buffer) //filename:用来存储 Path+filename buffer:用来存储
{
if (NULL == filename || buffer == NULL)
{
return -1;
}
//打开文件
FILE* fp = fopen(filename, "rb");//rb 以读的方式打开
//判断是否成功打开了文件
if (NULL == fp )
{
printf("Fopen fail! \n");
return -2;
}
//测量文件字节数(偏移量 三板斧 都得要
fseek(fp, 0, SEEK_END);将位置指针移动到文件末尾
int length = ftell(fp); // file size 确定文件的大小
fseek(fp, 0, SEEK_SET);//将位置指针移动到文件开头
int size = fread(buffer, 1,length,fp); //每次读取一个字节 从fp的指向开始 每次读1个字节 存放到buffer中 要执行length次
//判断两者长度是否一致 也就是读出来的数据大小是否等于文件大小
if (size != length)
{
printf("FileRead error ! %d \n",size);
return -3;
}
//关闭文件
fclose(fp);
//返回长度
return size;
}
//数据库中存储图片数据
int MySQL_WriteImg(MYSQL *mysql,char *buffer, int length)
{
if (mysql == NULL || buffer == NULL || length <= 0) return -1;
MYSQL_STMT* stmt = mysql_stmt_init(mysql);//初始化数据缓存
int ret = mysql_stmt_prepare(stmt, SQL_INSERT_TB_USER_IMG, strlen(SQL_INSERT_TB_USER_IMG));
if (ret)
{
printf("mysql_stmt_prepare is error ! %s \n",mysql_error(mysql));
return -2;
}
//绑定数据
MYSQL_BIND parme = { 0 }; //用于语句输入和返回值 通常和stmt绑定使用
parme.buffer_type = MYSQL_TYPE_LONG_BLOB;
parme.buffer = NULL;
parme.is_null = 0;
parme.length = NULL;
ret = mysql_stmt_bind_param(stmt,&parme);
if (ret)
{
printf("mysql_stmt_bind_param is error ! %s \n", mysql_error(mysql));
return -3;
}
//发送数据到数据库服务器中
ret = mysql_stmt_send_long_data(stmt, 0, buffer, length);
if (ret)
{
printf("mysql_stmt_send_long_data is error ! %s \n", mysql_error(mysql));
return -4;
}
//存储到表中
ret = mysql_stmt_execute(stmt);
if (ret)
{
printf("mysql_stmt_execute is error ! %s \n", mysql_error(mysql));
return -5;
}
//以上执行完毕关闭stmt
ret = mysql_stmt_close(stmt);
if (ret)
{
printf("mysql_stmt_close is error ! %s \n", mysql_error(mysql));
return -6;
}
return ret;
}
//从数据库中读取图片资源写入到磁盘
int MySQL_ReadImg(MYSQL *mysql,char * buffer, int length)
{
if (mysql == NULL || buffer == NULL || length <= 0) return -1;
MYSQL_STMT* stmt = mysql_stmt_init(mysql);//初始化数据缓存
//执行语句拿到返回值存储到stmt
int ret = mysql_stmt_prepare(stmt, SQL_SELECT_TB_USER_IMG, strlen(SQL_SELECT_TB_USER_IMG));
if (ret)
{
printf("mysql_stmt_prepare is error ! %s \n", mysql_error(mysql));
return -2;
}
//以下都是数据处理
//绑定结果
MYSQL_BIND result = { 0 }; //用于语句输入和返回值 通常和stmt绑定使用
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 is error ! %s \n", mysql_error(mysql));
return -3;
}
//执行语句
ret = mysql_stmt_execute(stmt);
if (ret)
{
printf("mysql_stmt_execute is error ! %s \n", mysql_error(mysql));
return -4;
}
//返回结果
ret = mysql_stmt_store_result(stmt);
if (ret) {
printf("mysql_stmt_store_result : %s\n", mysql_error(mysql));
return -5;
}
//数据显示 取出单行可以不需要外循环
while (1)
{
//mysql_stmt_fetch 抓取返回的数据集:stmt 的下一行数据
ret = mysql_stmt_fetch(stmt);
if (ret != 0 && ret != MYSQL_DATA_TRUNCATED) break; // MYSQL_DATA_TRUNCATED 出现数据截短 块存储分片 \
当mysql_stmt_fetch返回0时意味着数据读取完毕
int start = 0;
while (start<(int)total_length)
{
result.buffer = buffer + start; //result.buffer和传入的参数buffer使用的是一个内存空间
result.buffer_length = 1; //buffer_length buffer的实际大小也就是每次接受数据的最大长度
mysql_stmt_fetch_column(stmt, &result, 0, start);//mysql_stmt_fetch_column:当前行获取一列数据 s
//stmt:存储结果;
//result:保存返回数据的缓存空间;
//0:因为我们查询的数据列只有一个所以是第0个写0
//start:从什么位置开始的偏移量
start += result.buffer_length; //获取下一个偏移量 也就是当前start代表的偏移量+buffer_length的长度
}
}
//关闭stmt
mysql_stmt_close(stmt);
//返回 数据总长
return total_length;
}
//将图片数据写入磁盘
int WirteImg(char* filename, char* buffer, int length) //写到哪个文件中 写入的数据是哪些 写入的长度是多少
{
if (filename == NULL || buffer == NULL || length <= 0) return -1;
FILE* fp = fopen(filename,"wb"); //wb 以写的方式打开
//判断是否成功打开了文件
if (NULL == fp)
{
printf("Fopen fail! \n");
return -2;
}
int size = fwrite(buffer, 1, length, fp);//每次读取一个字节 从fp的指向存放 每次读1个字节 要执行length次
//判断两者长度是否一致 也就是读出来的数据大小是否等于文件大小
if (size != length)
{
printf("FileWrite error!%d \n", size);
return -3;
}
fclose(fp);
}
int main()
{
//注:mysql的两个接口以返回0作为失败
MYSQL mysql;
if (NULL == mysql_init(&mysql)) //初始化数据库
{
printf("mysql_init :%s \n", mysql_error(&mysql)); //mysql提供了统一的错误值
return -1;
}
//mysql_real_connect返回非0成功
if (!mysql_real_connect(&mysql, yang_db_server_ip,
yang_db_server_username, yang_db_server_password,
yang_db_server_definedb, yang_db_server_port, NULL, 0))//第一个参数是定义的数据库对象 第二个是IP地址 三四是用户名和密码 第五个是默认链接数据库名 第六个是端口号 七八置空
{
printf("mysql_real_connect:%s \n", mysql_error(&mysql));
goto Exit;
}
#if 1
sel(&mysql);
#endif
//读取磁盘的图片资源写入到mysql服务器中
#if 1
printf("case : mysql --> read image and write mysql\n");
char buffer[FILE_IMAGE_LENGTH] = { 0 };
int length = ReadImg("1.jpg", buffer); //图片和代码不在一个文件下用绝对路径,在可以直接写文件名
if (length < 0)
{
printf("length : %d \n", length);
goto Exit;
}
printf("length : %d \n", length);
MySQL_WriteImg(&mysql, buffer, length);
#endif // 1
//读取数据库中的图片资源并写入磁盘
#if 1
printf("case : mysql --> read mysql and write image\n");
char buffers[FILE_IMAGE_LENGTH] = { 0 };
memset(buffers, 0, FILE_IMAGE_LENGTH);
int len = MySQL_ReadImg(&mysql, buffers, FILE_IMAGE_LENGTH);
WirteImg("a.jpg", buffers,len);
#endif
#if 0
//insert----SQL
//mysql_real_query返回0成功
if (mysql_real_query(&mysql, SQL_INSERT_TB_USER, strlen(SQL_INSERT_TB_USER)))
{
printf("mysql_real_query :%s \n ", mysql_error(&mysql));
goto Exit;
}
#endif
#if 0
printf("case : mysql --> delete \n");
//delete----SQL
//mysql_real_query返回0成功
if (mysql_real_query(&mysql, SQL_CALL_PROC_TB_USER, strlen(SQL_CALL_PROC_TB_USER)))
{
printf("mysql_real_query :%s \n ", mysql_error(&mysql));
goto Exit;
}
#endif
#if 1
sel(&mysql);
#endif
Exit:
mysql_close(&mysql);
return 0;
}