将图像读取和写入 SQLite DB 以供 iPhone 使用

Posted

技术标签:

【中文标题】将图像读取和写入 SQLite DB 以供 iPhone 使用【英文标题】:Reading and writing images to an SQLite DB for iPhone use 【发布时间】:2010-10-13 05:19:46 【问题描述】:

我已经建立了一个 SQLite 数据库,目前可以完美地读写NSStrings。我还想将图像存储在数据库中并稍后调用。我已经阅读了一些关于使用 NSData 和编码图像的内容,但我并不完全确定我想要做什么的语法是什么。任何代码 sn-ps 或示例将不胜感激。

我目前的流程是这样的: UIImagePickerController -> 用户从照片中选择图片 -> selectedImage 设置为 UIImageView 的实例 -> 现在我想获取这张图片并将其存储在数据库中

我应该提到,这个调用最终将被对远程服务器的调用所取代。不确定这是否会对性能产生影响。

【问题讨论】:

【参考方案1】:

您需要将 UIImageView 中托管的 UIImage 转换为二进制 BLOB 以存储在 SQLite 中。为此,您可以使用以下内容:

NSData *dataForImage = UIImagePNGRepresentation(cachedImage);
sqlite3_bind_blob(yourSavingSQLStatement, 2, [dataForImage bytes], [dataForImage length], SQLITE_TRANSIENT);

这将生成图像的 PNG 表示,将其存储在 NSData 实例中,然后将 NSData 中的字节绑定为 SQL 查询中第二个参数的 BLOB。如果您愿意,可以使用上面的 UIImageJPEGRepresentation 以该格式存储。您需要将 BLOB 列添加到 SQLite 数据库中的相应表中。

要检索此图像,您可以使用以下命令:

NSData *dataForCachedImage = [[NSData alloc] initWithBytes:sqlite3_column_blob(yourLoadingSQLStatement, 2) length: sqlite3_column_bytes(yourLoadingSQLStatement, 2)];       
self.cachedImage = [UIImage imageWithData:dataForCachedImage];
[dataForCachedImage release];

【讨论】:

谢谢布拉德!今天下午晚些时候我会试试这个。看起来它可以解决问题。 我意识到这不是我想做的。将文件保存到服务器上的 URL 是一种更好的方法。 如果这对应用程序最有效,那么这就是要走的路。当我想要一个可以捆绑在一个应用程序中的文件时,我已经将图像存储在数据库中,该应用程序将保存一些初始数据。它使文件系统更加干净。 不会降低性能吗?我不认为这是一个好的解决方案【参考方案2】:

一种选择(在使用 SQL 时通常是首选)是将图像写入系统上的文件并将路径(或某种其他类型的标识符)存储在数据库中。

【讨论】:

我真的不知道为什么有人会将二进制文件存储在数据库中。对我来说似乎很疯狂。所以我认为数据库中的元数据是最好的情况。 你能给我看一个这样的代码示例吗?我可以看到保存到文件的好处。 经过几天的谷歌搜索。我已经实现并执行了这个想法。如果有人需要,我会发布一些代码。 link - 由 sqlite 团队自己比较性能 sqlite 外部与内部 blob 存储。【参考方案3】:

Apple 的建议是不要将 BLOB 存储在大于 ~2 KB 的 SQLite 数据库中。

SQLite 将数据库组织成页面。每页大小为 4 KB。当您从 SQLite 数据库文件中读取数据时,它会将这些页面加载到内部页面缓存中。在 iPhone 上,我认为这个缓存的大小默认为 1 兆字节。这使得读取相邻记录的速度非常快,因为它们可能已经在页面缓存中。

当 SQLite 将您的数据库记录读入内存时,它会读取整个记录以及它占用的所有页面。因此,如果您的记录包含 BLOB,它可能会占用很多页面,您将从缓存中弹出现有页面并用 BLOB 记录的页面替换它们。

如果您只是扫描并加载所有 BLOBS 以对它们执行某些操作(例如显示它们),这还不错。但是,如果说您执行了一个查询,只是想获取一些与 BLOB 位于同一行的数据,则该查询将比记录不包含大 BLOB 时慢得多。

因此,您至少应该将 BLOB 数据存储在单独的表中。例如:

CREATE TABLE blobs ( id INTEGER PRIMARY KEY, data BLOB );
CREATE TABLE photos ( id INTEGER PRIMARY KEY, name TEXT, blob_id INTEGER, 
    FOREIGN KEY(blob_id) REFERENCES blobs(id) );

或者更好的是,将 BLOB 数据存储为 SQLite 数据库之外的文件。

请注意,可以使用 SQL PRAGMA statements 调整页面缓存大小(如果您不使用 CoreData)。

【讨论】:

Apple 在哪里推荐?【参考方案4】:

将图像写入 SQLite 数据库

if(myImage != nil)
    NSData *imgData = UIImagePNGRepresentation(myImage);
    sqlite3_bind_blob(update_stmtement, 6, [imgData bytes], [imgData length], NULL);    
    
    else 
        sqlite3_bind_blob(update_stmtement, 6, nil, -1, NULL);
    

从 SQLite DB 读取:

NSData *data = [[NSData alloc] initWithBytes:sqlite3_column_blob(init_statement, 6) length:sqlite3_column_bytes(init_statement, 6)];
        if(data == nil)
            NSLog(@"No image found.");
        else
            self.pictureImage = [UIImage imageWithData:data];   

【讨论】:

【参考方案5】:

您应该首先在文件系统上写入图像。然后获取图像路径并将该图像路径(URL)作为文本存储在sqlite中。

【讨论】:

【参考方案6】:

最佳做法是压缩图像并将其存储在数据库或文件系统中。如果您不关心图像的分辨率,您可以继续使用,甚至可以使用以下方法调整图像大小:

   UIGraphicsBeginImageContext(newSize);  
   [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];   
   UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();    
   UIGraphicsEndImageContext();

之后,您可以将UIImageJPEGRepresentation 用于jpeg 图像,其值为“0”以实现最大压缩。或者您可以使用UIImagePNGRepresentation 处理 png 图片

【讨论】:

以上是关于将图像读取和写入 SQLite DB 以供 iPhone 使用的主要内容,如果未能解决你的问题,请参考以下文章

使用 fmdb 写入 sqlite db?

Django:独立于应用程序的读取和写入的多个数据库

dataframe to sqlite写入读取数据库

将结果写入存储以供查询时出错。无法读取未定义的属性“查询”

如何从我的 servlet 类访问放置在 /tmp 文件夹中的 sqlite db 文件?

VB.Net 向 SQLite-DB 写入大量数据