Извлечение большого блоба из базы данных Android sqlite
Я хранил куски двоичных данных (protobufs) в базе данных sqlite приложения для Android, не понимая, что Android Cursor
может содержать максимум 1 МБ данных. Теперь я знаю, что я должен был хранить эти двоичные капли в файлах и ссылался только на файлы в записях базы данных sqlite.
Мне нужно обновить базу данных (приложение использовалось некоторое время), чтобы переместить эти двоичные фрагменты в файлы. Проблема заключается в том, что некоторые пользовательские данные могут уже превышать ограничение 1 МБ, и я не могу получить его из базы данных (доступ к результирующему Cursor
для одной строки, содержащей большой blob, вызывает IllegalStateException: Couldn't read row 0, col 0 from CursorWindow. Make sure the Cursor is initialize before accessing data from it
).
Как получить бинарные капли, превышающие предел 1 МБ Cursor
, которые были сохранены в базе данных sqlite?
Ответы
Ответ 1
Вы можете читать большие капли в кусках. Сначала выясните, какие из них нуждаются в этом лечении:
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 или к обычным функциям запроса API C с NDK, но это было бы слишком сложно в этом случае.
Ответ 2
CL. ответ будет только с blobs < 5MB. Если вы попытаетесь использовать его с блобами размером более 5 мегабайт, вы все равно получите исключение. Чтобы получить большие капли, вам нужно использовать библиотеку 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();
}