(*)本文系本博客原创,如需转载请注明原作者!

原文作者:戴晓天,云飞实验室

联系方式:automatic.dai@gmail.com

原文来自:www.yfworld.com

SQLite是轻量级数据库,但其功能齐全,当然也包括了对BLOB对象的操作功能。但今天在做SQLite的BLOB功能测试时,出现了读取出的数据与写入数据不一致的情况,这让我十分费解。

测试程序将一幅图片文件读入内存,写入数据库。之后从数据库中读出,再写出成图片文件。整个程序的执行过程示意如下:

1. 打开数据库

sqlite3_open("blob.db",&db);

 

2. 新建一个表,包含两个字段:name和item,其中name为varchar(128)是文件名,item为blob类型

sprintf( sql,"CREATE TABLE blob(id varchar(128) UNIQUE,item BLOB)" );
sqlite3_exec(db, sql, 0, 0, &zErrMsg);     // zErrMsg是错误代码

 

3. 准备一次blob传输,其中 ? 为占位符,之后要将其绑定

(*)stat为sqlite_stmt * 类型

sqlite3_prepare(db, "INSERT INTO blob values (1,?);", -1, &stat, 0);

 

4. 打开一个对象,以便将其绑定

(*)数据保存在pFile中,数据大小保存在filesize中,在下一步会用到。

fp = fopen("test.bmp", "rb");

//首先计算文件大小
fseek(fp, 0, SEEK_END);
filesize = ftell(fp);

fseek(fp, 0, SEEK_SET);

//将数据读入到缓冲区
pFile = new char[filesize];
size_t sz = fread(pFile, sizeof(char), filesize, fp);
fclose(fp);

 

5. 绑定数据并执行

sqlite3_bind_blob(stat, 1, pFile, filesize, NULL);
sqlite3_step(stat);
sqlite3_finalize(stat);  // Release sqlite_stmt

—————————————————————-

以上完成了blob数据的写入,现在将其读出。

6. 进行一次读出操作

sqlite3_prepare(db, "select * from blob;", -1, &stat, 0);
sqlite3_step(stat);

 

7. 得到Blob文件的指针和大小

const void *pBlob = sqlite3_column_blob(stat, 1); // Get blob,1为列号
int blob_size = sqlite3_column_bytes(stat, 1);    // Get size

 

8. 将其写入文件

fp = fopen("test_output.bmp", "w+");

size_t sz = fwrite(pBlob, sizeof(char), blob_size, fp);

 

至此,一个Blob对象的写入/读出操作就完成了。

—————————————————————-

可是问题来了,得到的图片文件与源样本存在很大差别!

源图片:

最后得到的文件:


仔细观察,可以发现两幅图片还是有几分相似的,而出错的图片好像发生了扭曲一般。

首先,我考虑到是可能是缓冲数组的边界值没有取好,造成了部分文件丢失。可在仔细核对过缓冲区大小后,并没有发现任何问题。打开两个文件的属性进行对照:

源图片:

读取出的图片:


可见读取出的图片反而更大一些,这显然不是丢失了数据,而是增加了数据。好好的会增加什么数据呢?通过UltraEdit打开两个图片的二进制文件,我找到了一些眉目:

源文件:

目的文件:

通过对比,我发现凭空增加的字符是0x0D,这是ASC码中的回车字符。像这样的字符出现了好几处,我想就是这个原因导致了两个文件大小不一致。而且我发现,所有增加的0x0D字符并无周期规律,但都是紧跟在0x0A(换行符)之前的。
这下终于发现了问题的所在:程序将我的文件当成了文本在处理!在WINDOWS的文本格式中,所有的换行符之前都会紧跟一个回车符。

自然而然的,我将问题定位到我不熟悉的SQLite上。我首先怀疑,SQLite在处理我的BLOB对象时,当作了文本处理。但查阅了它的Document之后,我并没有找到sqlite3_column_blob()有关于具体数据类型是纯二进制还是文本的参数。我操作BLOB的方法与网上介绍的方法也并无异处。

我决定将我的程序分块调试,先定位到底是文件操作出了问题,还是数据库方面出了问题;之后再具体去看是写的时候还是读的时候遇到了问题。照着这个思路,我准备开始分块调试。

中间太累了,我睡了一觉。刚要睡着,灵感来了。我起身打开电脑屏幕,添加了一个字母,运行。

fp = fopen("test_output.bmp", "wb+");

哈,问题解决了。原来,我在读文件操作时用了binary模式,写操作时却粗心没有在模式中加”b”,这样就用文本模式写入了。可见,不一定总是在新地方翻船。有时候,自己熟悉的地方也有存在潜在问题的可能性。

在此分享给大家,一是希望与我有同样问题的可以顺利解决;二是警戒自己不要在这种细节方面出问题。

 

【修订历史】

V1.1    24/03/2015: 修改了文章版式,修正了更新网站版本后的排版问题。将代码从plain text改为通过代码插件高亮显示。


>> 本文章版权归作者所有,如需转载请联系作者授权许可。
>> 原文来自: 云飞机器人实验室
>> 原文地址: 数据库 | SQLite BLOB的使用、出现乱码问题并解决
>> 关于我们: 关于云飞实验室
>> 支持我们: 帮助我们可持续发展


作者

1 thought on “数据库 | SQLite BLOB的使用、出现乱码问题并解决

  1. 哈,问题解决了。原来,我在读文件操作时用了binary模式,写操作时却粗心没有在模式中加“b”,这样就用文本模式写入了。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据