为离线 Web 应用程序存储图像数据(客户端存储数据库)

Posted

技术标签:

【中文标题】为离线 Web 应用程序存储图像数据(客户端存储数据库)【英文标题】:Storing Image Data for offline web application (client-side storage database) 【发布时间】:2012-12-16 07:15:26 【问题描述】:

我有一个使用应用缓存的离线 Web 应用程序。我需要为它提供大约 10MB - 20MB 的数据,它将保存(客户端)主要由 PNG 图像文件组成。操作如下:

    Web 应用程序下载并安装在 appcache 中(使用清单) 来自服务器 PNG 数据文件的 Web 应用程序请求(如何?- 请参阅下面的替代方案) Web 应用偶尔会与服务器重新同步,并对 PNG 数据库进行小部分更新/删除/添加 仅供参考:服务器是一个 JSON REST 服务器,可以将文件放在 wwwroot 中以供拾取

这是我目前对处理二进制 blob 存储的基于客户端的“数据库”的分析

见底部更新

AppCache(通过清单添加所有 PNG,然后按需更新)

CON:PNG 数据库项目的任何更改都将意味着完整下载清单中的所有项目(真是个坏消息!)

网络存储

CON:专为 JSON 存储而设计 CON:只能通过 base64 编码存储 blob(由于解码成本,可能是致命缺陷) CON:webStorage http://htmlui.com/blog/2011-08-23-5-obscure-facts-about-html5-localstorage.html 的硬限制为 5MB

PhoneGap 和 SQLLite

CON:赞助商将拒绝它作为需要认证的原生应用程序

ZIP 文件

服务器创建一个 zip 文件,将其放在 wwwroot 中,并通知客户端 用户必须手动解压缩(至少我是这样看的)并保存到客户端文件系统 Web 应用使用 FileSystem API 来引用文件 CON:ZIP 可能太大(zip64?),创建时间过长 CON:不确定 FileSystem API 是否总是可以从沙盒中读取(我认为是这样)

USB 或 SD 卡(回到石器时代......)

用户在离线前将位于服务器本地 所以我们可以让他插入一张 SD 卡,让服务器用 PNG 文件填充它 然后用户将其插入笔记本电脑、平板电脑 Web 应用程序将使用 FileSystem API 来读取文件 CON:不确定 FileSystem API 是否总是可以从沙盒中读取(我认为是这样)

WebSQL

CON:w3c 已经放弃了它(非常糟糕) 我可能会考虑使用 IndexedDB 和 WebSQL 作为后备的 javascript 包装器

文件系统 API

Chrome 支持 Blob 的读/写 CON:不清楚 IE 和 FireFox(IE10,有非标准 msSave) caniuse.com 报告了 iosandroid 支持(但同样,这只是 JSON 的 r/w,还是包含用于编写的完整 blob API? CON:FireFox 不喜欢 FileSystem API,不清楚他们是否支持保存 blob:https://hacks.mozilla.org/2012/07/why-no-filesystem-api-in-firefox/ PRO:根据 jsperf http://jsperf.com/indexeddb-vs-localstorage/15(第 2 页),比 IndexedDB 快得多

索引数据库

对 IE10、FireFox 的良好支持(保存、读取 blob) 比文件系统(删除、更新)速度快且易于管理 PRO:见速度测试:http://jsperf.com/indexeddb-vs-localstorage/15 请参阅这篇关于在 IndexedDB 中存储和显示图像的文章:https://hacks.mozilla.org/2012/02/storing-images-and-files-in-indexeddb/ CON:我确认 Chrome 尚不支持 blob 写入(当前错误,但不清楚何时修复) 更新:A June 2014 blogpost 建议 Chrome 现在支持 IndexedDB 中的 blob 更新:This caniuse/indexeddb 确认:“Chrome 36 及以下版本不支持 Blob 对象作为 indexedDB 值。”;建议 >Chrome36 支持 Blob 对象。

LawnChair JavaScript 包装器 http://brian.io/lawnchair/

PRO:非常干净的 IndexedDB、WebSQL 或您拥有的任何数据库的包装器(想想 polyfill) CON:无法存储二进制 blob,只能存储 data:uri(base64 编码)(由于解码成本,可能存在致命缺陷)

IndexedDB JQUERY polyFill https://github.com/axemclion/jquery-indexeddb

Parashuram 为原始 IndexedDB 接口编写了一个不错的 JQUERY 包装器 PRO:大大简化了 IndexedDB 的使用,我希望为 Chrome FileSystemAPI 添加一个 shim/polyfill CON:它应该处理 blob,但我无法让它工作

idb.filesystem.js http://ericbidelman.tumblr.com/post/21649963613/idb-filesystem-js-bringing-the-html5-filesystem-api

Eric Bidelman @ Google 编写了一个经过良好测试的 PolyFill FileSystem API,它使用 Indexed DB 作为后备 专业版:FileSystem API 非常适合存储 blob PRO:在 FireFox 和 Chrome 上运行良好 PRO:非常适合与基于云的 CouchDB 同步 CON:不清楚原因,但它不适用于 IE10

PouchDB JavaScript 库http://pouchdb.com/

非常适合将 CouchDB 与本地 DB 同步(使用 WebSQL 或 IndexedDB(虽然不是我的问题) CON:没有缺点,PouchDB 现在支持所有最新浏览器(IE、Chrome、Firefox、移动版 Chrome 等)以及许多旧浏览器的二进制 blob。当我第一次发布这篇文章时,情况并非如此。

注意:要查看 PNG 的 data:uri 编码,我在以下位置创建了一个示例:http://jsbin.com/ivefak/1/edit

所需/有用/不需要的功能

客户端上没有本机(EXE、PhoneGap、ObjectiveC 等)应用(纯 Web 应用) 只需要在最新的 Chrome、FireFox、IE10 笔记本电脑上运行 强烈希望为 Android 平板电脑提供相同的解决方案(IOS 也可以),但只需要一个浏览器即可工作(FF、Chrome 等) 快速初始数据库填充 要求:Web 应用程序从存储(数据库、文件)中快速检索图像 不适用于消费者。我们可以限制浏览器,并要求用户进行特殊设置和任务,但让我们尽量减少

IndexedDB 实现

有一篇关于 IE、FF 和 Chrome 如何在内部实现此功能的优秀文章:http://www.aaron-powell.com/web/indexeddb-storage 简而言之: IE 使用与 Exchange 和 Active Directory 相同的数据库格式用于 IndexedDB Firefox 正在使用 SQLite,因此在 SQL 数据库中实现了一个 NoSQL 数据库 Chrome(和 WebKit)正在使用具有 BigTable 传统的 Key/Value 存储

我目前的结果

我选择使用 IndexedDB 方法(并使用适用于 Chrome 的 FileSystemAPI 进行 polyfill,直到他们提供 blob 支持) 为了获取图块,我遇到了一个难题,因为 JQUERY 的人正在为将它添加到 AJAX 中而苦恼 我使用了 Phil Parsons 的 XHR2-Lib,它非常类似于 JQUERY .ajax() https://github.com/p-m-p/xhr2-lib 100MB 下载的性能(IE10 4s、Chrome 6s、FireFox 7s)。 我无法让任何 IndexedDB 包装器用于 blob(lawnchair、PouchDB、jquery-indexeddb 等) 我推出了自己的包装器,性能是(IE10 2s、Chrome 3s、FireFox 10s) 对于 FF,我假设我们看到了将关系数据库 (sqllite) 用于非 sql 存储的性能问题 注意,Chrome 具有出色的调试工具(开发人员选项卡、资源),可用于检查 IndexedDB 的状态。

最终结果发布在下面作为答案

更新

PouchDB 现在支持所有最新浏览器(IE、Chrome、Firefox、移动版 Chrome 等)以及许多旧版浏览器的二进制 blob。当我第一次发这篇文章时,情况并非如此。

【问题讨论】:

webstorage 不支持 json 但支持字符串,因此您可以对 imagez 进行 base64 编码并将它们作为 dataurl 提供。 好的,但对于 20MB 的图像可能不是最佳的(或在配额内),这些图像实际上是易滑的地图图块,需要在缩放和平移时由 LEAFLET 地图应用程序快速获取和显示。 你所做的研究很有帮助。 我的观点是,如果您使用的是 png 图像,则不需要处理二进制 blob。 您说得对,您介意我更新文档以反映您的意见吗? 【参考方案1】:

我有地图缓存examples(打开示例,发现区域和缩放,离线切换和发现的区域可用)。

map.js - 离线瓦片的地图层,storage.js - 基于IndexedDb和WebSQL的存储实现(但这只是性能较差的测试实现)。

对于站点文件(html、css、js 等),我更喜欢使用应用程序缓存。 对于存储,我更喜欢使用 Indexed DB(支持 blob)、Web SQL(仅 base64)、FileWriter(支持 blob,但仅 chrome)。坦率地说,存储对此是个大问题。您需要将它们全部混合的最快的键值解决方案。我认为使用现有解决方案是一个不错的决定。 为了获取数据,我使用了带有 CORS 的画布。但我在考虑 WebWorkers 和 XHR2,这可能比 canvas 更好,因为 canvas 在不同的浏览器和其他浏览器中存在一些 CORS 问题(例如,this title 存储在 bad in opera)。

有关 20 亿城市规模的其他信息 (Minsk):

缩放 - 9,图块 - 2,大小 - 52 kb,上一个 - 52 kb; 缩放 - 10,图块 - 3,大小 - 72 kb,上一个 - 124 kb; 缩放 - 11,图块 - 7,大小 - 204 kb,上一个 - 328 kb; 缩放 - 12,图块 - 17,大小 - 348 kb,上一个 - 676 kb; 缩放 - 13,图块 - 48,大小 - 820 kb,上一个 - 1.5 mb; 缩放 - 14,图块 - 158,大小 - 2.2 mb,上一个 - 3.7 mb; 缩放 - 15,图块 - 586,大小 - 5.5 mb,上一个 - 9.3 mb; 缩放 - 16,图块 - 2264,大小 - 15 mb,上一个 - 24.3 mb;

【讨论】:

我认为这些是 EGPS3857 格式的 JPG 瓦片,对吧?因为我正在使用传单并进行光栅覆盖,所以我不得不使用 PNG。还可以查看我的使用 PouchDB 的演示(它在下面使用 IDB)。 ***.com/questions/16721312/… 哦,是的,您正在即时缓存,但是您知道我可以去哪里获取预先构建的 OSM 地图(全球)以缩小 10 或 11 或 12 吗?我们会将其保存在我们的离线服务器上。 不,使用 PNG 和默认投影 (EGPS:3857) 但无论 JPEGPNG 因为它被 img 标签或 canvas 使用。在我的示例中,如果您知道切片键(每个存储的切片为storage.add('x_y_z', 'data:image/png;base64,...')),您可以只预加载切片,但如果只知道边界(多边形)和缩放,您总是可以获取它们。 我想确保我们没有语言问题。你有什么地方可以得到一套全球范围的 OSM 滑动图块(PNG 或 JPG)来缩放 10 级? 您可以从tile.osm.org(mapnik 渲染器)中获取图块。例如http://tile.openstreetmap.org/10/590/329.png (zoom/x/y.png)。此图块具有 Access-Control-Allow-Origin: * 标头,因此您可以通过 ajax 获取它们或通过画布获取数据 uri (base64)。您已经可以使用manifest.jsonid: 0-0-0 下载图块,但您必须确保拥有正确的zoomxy 序列。【参考方案2】:

PNG 滑图的离线 blob 缓存结果

测试

171 个 PNG 文件(共 3.2MB) 经过测试的平台:Chrome v24、FireFox 18、IE 10 应该也适用于 Android 版 Chrome 和 FF

从网络服务器获取

使用 XHR2(几乎所有浏览器都支持)从 Web 服务器下载 blob 我选择了 Phil Parsons 的 XHR2-Lib,它非常类似于 JQUERY .ajax() https://github.com/p-m-p/xhr2-lib

存储

用于 IE 和 FireFox 的 IndexedDB Chrome:Polyfill(使用 FileSystem API 存储的 blob,引用保存在 IndexedDB 中)polyfill 必读文章“浏览器如何存储 IndexedDB 数据” http://www.aaron-powell.com/web/indexeddb-storage 注意:FireFox 将 SQLlite 用于 NOSQL IndexedDB。这可能是性能缓慢的原因。 (blob 单独存储) 注意:Microsoft IE 使用可扩展存储引擎: http://en.wikipedia.org/wiki/Extensible_Storage_Engine 注意:Chrome 使用 LevelDB http://code.google.com/p/leveldb/

显示

我正在使用 Leaflet http://leafletjs.com/ 来显示地图图块 我使用 Ishmael Smyrnow 的功能性切片图层插件从数据库中获取切片图层 https://github.com/ismyrnow/Leaflet.functionaltilelayer 我将基于 DB 的切片层与纯本地 (localhost://) 存储进行了比较 性能没有明显差异!在使用 IndexedDB 和本地文件之间!

结果

Chrome:获取 (6.551s)、存储 (8.247s)、总运行时间:(13.714s) FireFox:获取 (0.422s)、存储 (31.519s)、总经过时间:(32.836s) IE 10:获取(0.668 秒),存储:(0.896 秒),总运行时间:(3.758 秒)

【讨论】:

【参考方案3】:

根据您的要求,我建议基于其他两个开发新的 polyfill: FileSystem API to IndexedDBIndexedDB 到 WebSQL — 是最好的选择。

前者将支持在 Chrome (FileSystem API) 和 Firefox (IndexedDB) 中存储 blob,而后者应支持 Android 和 iOS (WebSQL)。所需要的只是让这些 polyfill 一起工作,我想这并不难。

注意:由于我在网络上找不到任何关于此的信息,因此您应该测试使用 WebSQL polyfill 存储 blob 是否适用于 iOS 和 Android。看起来它应该可以工作:

var sql = ["CREATE TABLE", idbModules.util.quote(storeName), "(key BLOB", createOptions.autoIncrement ? ", inc INTEGER PRIMARY KEY AUTOINCREMENT" : "PRIMARY KEY", ", value BLOB)"].join(" ")

Source

【讨论】:

我倾向于您的建议,但我正在等待其他人的意见。我没有方便的 android,但最好创建一个 jsBin 或 jsFiddle 并查看在 Android 上的工作原理。 这两个 blob 是不同的。 sqlite blob 在 javascript 中是 arraybuffer,而 js blob 在 sqlite 中没有等价物。 Blob 不能转换为 arraybuffer,尽管它可以在结构上被克隆。【参考方案4】:

几年前(不完全是石器时代),我使用了一个签名的 Java 小程序,它会查询其服务器的同步/更新要求,从服务器下载适当的文件并将它们保存在用户的文件系统(不是数据库)。该解决方案可能对您有用,尽管您需要有人编写小程序并对其进行签名。对于数据库解决方案,这样的小程序可以使用适用于大多数数据库的 jdbc,在合适的端口上使用 localhost(例如,3306 用于 mysql)。我相信小程序标签在 Html5 中已被弃用,但它仍然有效。没有使用 Android 平板电脑的经验,因此无法对此部分发表评论。

【讨论】:

我从 1968 年开始使用打卡机在 FORTRAN 中编程。所以石器时代的解决方案对我来说并不新鲜。

以上是关于为离线 Web 应用程序存储图像数据(客户端存储数据库)的主要内容,如果未能解决你的问题,请参考以下文章

HTML5离线应用与客户端存储

JavaScript中离线应用和客户端存储(cookiessessionStoragelocalStorage)

将数据库存储用于离线应用程序以外的用途

Html5学习之离线应用与客户端存储详解

将图像永久存储在离线 web 应用中 [Android WebView]

存储离线数据以在 ipad 应用程序中查询只读数据