从Android sqlite数据库中检索大blob

时间:2012-10-03 21:03:05

标签: android sqlite cursor blob protocol-buffers

我在Android应用程序的sqlite数据库中存储了大量二进制数据(protobufs),却没有意识到Android的Cursor只能容纳最多1MB的数据。我现在知道我应该将这些二进制blob存储在文件中,并且只引用sqlite数据库条目中的文件。

我需要升级数据库(应用程序已经使用了一段时间)才能将这些二进制块移动到文件中。问题是某些用户的数据可能已经超过了1MB的限制而且我无法从数据库中检索它(访问包含大blob的单行的结果Cursor会导致{{1} })。

如何检索大小超过sqlite数据库中存储的1MB IllegalStateException: Couldn't read row 0, col 0 from CursorWindow. Make sure the Cursor is initialize before accessing data from it限制的二进制blob?

2 个答案:

答案 0 :(得分:31)

你可以读取大块的碎片。首先找出哪些需要这种治疗:

SELECT id, length(blobcolumn) FROM mytable WHERE length(blobcolumn) > 1000000

然后使用substr读取块:

SELECT substr(blobcolumn,       1, 1000000) FROM mytable WHERE id = 123
SELECT substr(blobcolumn, 1000001, 1000000) FROM mytable WHERE id = 123
...

您还可以编译自己的SQLite副本并使用NDK访问BLOB stream I/O函数或C API的常规查询函数,但在这种情况下这将太复杂。

答案 1 :(得分:0)

CL。回答只有blob <5MB。如果你尝试使用大于5兆字节的blob,你仍然会得到异常。要获取大blob,您需要使用名为sqlite4java的库,该库使用对数据库的本机调用,而不使用游标。以下是使用此库获取大blob的示例:

SQLiteConnection sqLiteConnection=null;
SQLiteStatement sqLiteStatement=null;
try
{
    File databaseFile = context.getDatabasePath("database.db");
    sqLiteConnection=new SQLiteConnection(databaseFile);
    sqLiteConnection.open();
    sqLiteStatement=sqLiteConnection.prepare("SELECT blob FROM table WHERE id=?");
    sqLiteStatement.bind(1, id);
    sqLiteStatement.step();
    byte[] blob=sqLiteStatement.columnBlob(0);
}
finally
{
    if(sqLiteStatement!=null)
        sqLiteStatement.dispose();
    if(sqLiteConnection!=null)
        sqLiteConnection.dispose();
}