2012-10-03 54 views
17

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

我需要升级数据库(应用程序已使用了一段时间),以便将这些二进制块移动到文件。问题是某些用户的数据可能已经超过了1MB的限制,并且我无法从数据库中检索它(访问生成的Cursor对于包含大块的单个行会抛出IllegalStateException: Couldn't read row 0, col 0 from CursorWindow. Make sure the Cursor is initialize before accessing data from it)。

如何检索大于已存储在sqlite数据库中的1MB Cursor限制的二进制blob?

+0

嘿,谢谢!这个问题帮助我分析并解决了我面临的同样的问题! –

回答

27

您可以分段读取大块。首先找出哪些需要这种治疗:

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的复制和访问无论是BLOB stream I/O功能或使用NDK的C API的正常查询功能,但在这种情况下这太复杂了。

+0

非常感谢!这真的有帮助。我不知道SQLite的核心功能。完美工作! – ashughes

+0

你是否有任何有效的方法来添加这些块来组成一个完整的'byte []'? –

+0

@KamranAhmed你已经知道整个长度,所以分配一个大数组并复制块。 –

0

CL。答案只会与blob < 5MB。如果你尝试使用大于5兆字节的blob,你仍然会得到异常。要获取大块,您需要使用名为sqlite4java的库,该库使用本地调用数据库而不使用游标。下面是使用这个库来获取大块的例子:

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(); 
}