直接把文件放入数据库中比较适合小文件,方便管理,比如头像图片和声音,如果是较大型的文件建议不要直接存进数据库,而是放在服务器,把文件索引放在数据库。
MYSQL 中有个数据对象是 BLOB,即 Binary Large Object,顾名思义也就是二进制大型数据对象,用来记录二进制的数据,它有 4 种类型,分别是:tinyblob(255B)、blob(65KB)、mediumblob(16MB)、longblob(4GB)。
我在数据库中创建了一张 images 表,如下图:
先把用到的头文件和预处理写一下:
#include
#include
#include
#include
#include
#pragma comment(lib, "libmysql.lib")
#define BYTE unsigned char
#define FILE_MAX_SIZE (65 * 1024) /*文件最大65KB*/
接下来的任务就是怎么把数据记录到 img 字段,我用C语言写了个函数,函数接受文件路径:
void insert(char *path)
{
FILE *fp;
BYTE *img, data;
long cnt = 0;
MYSQL mysql;
char *sql;
/*读取文件*/
fp = fopen(path, "rb");
if (!fp)
{
printf("读取文件失败\n");
return;
}
img = malloc(FILE_MAX_SIZE); //分配65KB的内存
memset(img, FILE_MAX_SIZE, 0);
while (!feof(fp))
{
fread(&data, 1, 1, fp);
if (data == '\0') //将结束字符转义
{
img[cnt++] = '\\';
img[cnt++] = '0';
continue;
}
if (data == '\'' || data == '\\' /*|| data == '\"'*/) //这些字符也要转义
{
img[cnt++] = '\\';
}
img[cnt++] = data;
if (cnt == FILE_MAX_SIZE)
{
printf("文件超过65KB\n");
free(img);
fclose(fp);
return;
}
}
img[cnt] = '\0';
fclose(fp);
/*操作数据库*/
if (NULL == mysql_init(&mysql))
{
printf("初始化数据库失败\n");
return;
}
if (NULL == mysql_real_connect(&mysql, "localhost", "root", "password", "test", 0, NULL, 0))
{
printf("连接数据库失败\n");
return;
}
sql = malloc(126 + FILE_MAX_SIZE);
memset(sql, 126 + FILE_MAX_SIZE, 0);
sprintf(sql, "INSERT INTO images (img) VALUES ('%s')", img);
if (0 != mysql_real_query(&mysql, sql, strlen(sql)))
{
printf("执行SQL语句出错\n");
mysql_close(&mysql);
free(sql);
free(img);
return;
}
mysql_close(&mysql);
free(sql);
free(img);
printf("插入成功\n");
}
从以上代码可以看出整个过程是将文件以二进制形式读出,然后再执行 SQL 语句。
下面我要将文件从数据库中读取出来,存放本地,该函数结束文件路径和在数据库中的 id 字段:
void peek(char *filename, int id)
{
MYSQL mysql;
FILE *fp;
char sql[126];
MYSQL_RES *res;
MYSQL_ROW row;
long *length;
/*操作数据库*/
if (NULL == mysql_init(&mysql))
{
printf("初始化数据库失败\n");
return;
}
if (NULL == mysql_real_connect(&mysql, "localhost", "root", "password", "test", 0, NULL, 0))
{
printf("连接数据库失败\n");
return;
}
sprintf(sql, "SELECT img FROM images WHERE id=%d", id);
if (0 != mysql_real_query(&mysql, sql, strlen(sql)))
{
printf("执行SQL语句出错\n");
}
res = mysql_store_result(&mysql);
if (NULL == res)
{
printf("数据库中无结果\n");
mysql_close(&mysql);
}
row = mysql_fetch_row(res);
length = mysql_fetch_lengths(res); //得到img字段数据的长度
mysql_close(&mysql);
/*写入文件*/
fp = fopen(filename, "wb");
if (!fp)
{
mysql_free_result(res);
mysql_close(&mysql);
printf("创建文件失败\n");
return;
}
fwrite(row[0], 1, length[0], fp); //这里千万不能用strlen计算长度,因为文件中可能有很多结束标志字符'\0'
fclose(fp);
mysql_free_result(res);
mysql_close(&mysql);
printf("读取成功\n");
} 我开始被 strlen 的问题搞得晕头转向,心想不用 strlen 那我再用什么得到长度呢,还好后来找到了 mysql_fetch_lengths 这个函数。