我正在尝试通过压缩来最小化包含大量 HTML 的 sqlite3 数据库。我使用 python 创建 sqlite3 数据库,并尝试在 Android 上正确解压。
我使用 gzip 压缩 HTML 并将其作为 BLOB 存储在数据库中。这是我编写的用于创建 sqlite3 数据库的代码(在 Python 中):
from sys import stdin, argv
import sqlite3
import gzip
import cStringIO
def compressBuf(buf):
zbuf = cStringIO.StringIO()
zfile = gzip.GzipFile(mode = 'wb', fileobj = zbuf, compresslevel = 9)
zfile.write(buf)
zfile.close()
return zbuf.getvalue()
conn = sqlite3.connect(argv[1])
conn.text_factory = str
c = conn.cursor()
c.execute('''CREATE TABLE articles (
id INTEGER NOT NULL PRIMARY KEY,
name TEXT, category TEXT, html BLOB );''')
c.execute(' CREATE INDEX name_index on articles (name); ')
for line in stdin:
line = line.strip().split('\t')
line[-1] = sqlite3.Binary(compressBuf(line[-1]))
c.execute('INSERT INTO articles VALUES (?, ?, ?, ?);', line)
conn.commit()
c.close()
conn.close()
这是 Android 的代码片段:
Cursor cursor = db.rawQuery("SELECT html FROM articles WHERE id = " + id + " limit 1;", null);
cursor.moveToFirst();
byte[] zhtml = cursor.getBlob(0);
ByteArrayInputStream is = new ByteArrayInputStream(zhtml);
GZIPInputStream gis = new GZIPInputStream(is, zhtml.length);
我收到以下异常,抱怨标头不正确:
java.io.IOException: unknown format (magic number 213c)
at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:84)
at tw.cse.o0o.MyApp.WebServer$ArticleHandler$1.writeTo(WebServer.java:196)
at org.apache.http.entity.EntityTemplate.writeTo(EntityTemplate.java:76)
at org.apache.http.impl.entity.EntitySerializer.serialize(EntitySerializer.java:97)
at org.apache.http.impl.AbstractHttpServerConnection.sendResponseEntity(AbstractHttpServerConnection.java:182)
at org.apache.http.protocol.HttpService.handleRequest(HttpService.java:209)
at tw.cse.o0o.MyApp.WebServer.run(SQLHelper.java:90)
使用 Python 解释器,我可以确认 compressBuf 函数返回正确的 gzip 幻数 0x1f8b:
>>> compressBuf('test')
'\x1f\x8b\x08\x00 \xba:O\x02\xff+I-.\x01\x00\x0c~\x7f\xd8\x04\x00\x00\x00'
[编辑]
好吧,这就是我发现的:
在 Nexus One 上,getBlob() 函数会自动解压缩二进制数据,无论是 zlib 还是 gzip。错误日志中的213c是原始html的前两个字符。 然而,三星 Galaxy Tab(第一代)的情况并非如此。我仍在尝试找到一种在我的 Galaxy Tab 上解压缩的方法..
'\x21\x3c
-->> '!<'
或者 '<!'
取决于字节顺序。我建议您调查(二进制)gzip 压缩数据在传输过程中被填充的可能性。
我最近创建了一个 sqlite-compressions 扩展,它将
gzip
和 brotli
压缩、解压和测试功能添加到 sqlite 作为扩展(或者您可以直接从 Rust 代码中使用它)。
这将允许您使用 SQL 插入 HTML 并获取 HTML,而
html
列将存储为 gzip(您可能希望 brotli 稍慢但压缩效果更好):
INSERT INTO articles VALUES (..., gzip(?))
SELECT gzip_decode(html) FROM ...
我不太确定的唯一方面是 Android 是否允许加载自定义扩展 - 这需要验证。