Подтвердить что ты не робот

Извлечение большого блоба из базы данных 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?

4b9b3361

Ответ 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();
}