Чтение и запись изображений в базу данных SQLite для iPhone - PullRequest
22 голосов
/ 13 марта 2009

Я настроил базу данных SQLite, которая в настоящее время отлично читает и пишет NSString s. Я также хочу сохранить изображение в базе данных и вспомнить его позже. Я немного прочитал об использовании NSData и кодировании изображения, но я не совсем уверен, каков синтаксис того, что я хочу сделать. Любые фрагменты кода или примеры будут с благодарностью.

Мой текущий процесс выглядит так: UIImagePickerController -> Пользователь выбирает изображение из фотографий -> selectedImage устанавливается на экземпляр UIImageView -> Теперь я хочу взять это изображение и сохранить его в БД

Я должен упомянуть, что этот вызов в конечном итоге будет заменен вызовом на удаленный сервер. Не уверен, что это влияет на производительность.

Ответы [ 6 ]

31 голосов
/ 13 марта 2009

Вам потребуется преобразовать UIImage, размещенный в вашем UIImageView, в двоичный BLOB для хранения в SQLite. Для этого вы можете использовать следующее:

NSData *dataForImage = UIImagePNGRepresentation(cachedImage);
sqlite3_bind_blob(yourSavingSQLStatement, 2, [dataForImage bytes], [dataForImage length], SQLITE_TRANSIENT);

Это сгенерирует PNG-представление вашего изображения, сохранит его в экземпляре NSData, а затем свяжет байты из NSData как BLOB для второго аргумента в вашем запросе SQL. Используйте UIImageJPEGRepresentation в приведенном выше, чтобы сохранить в этом формате, если хотите. Вам потребуется добавить столбец BLOB в соответствующую таблицу в вашей базе данных SQLite.

Чтобы получить это изображение, вы можете использовать следующее:

NSData *dataForCachedImage = [[NSData alloc] initWithBytes:sqlite3_column_blob(yourLoadingSQLStatement, 2) length: sqlite3_column_bytes(yourLoadingSQLStatement, 2)];       
self.cachedImage = [UIImage imageWithData:dataForCachedImage];
[dataForCachedImage release];
9 голосов
/ 15 апреля 2011

Apple не рекомендует хранить BLOB в базах данных SQLite, размер которых превышает ~ 2 килобайта.

SQLite организует базы данных в страницы. Каждая страница имеет размер 4 килобайта. Когда вы читаете данные из файла базы данных SQLite, он загружает эти страницы во внутренний кеш страниц. На iPhone я думаю, что этот кэш по умолчанию имеет размер 1 мегабайт. Это делает чтение соседних записей очень быстрым, потому что они, вероятно, уже будут в кеше страницы.

Когда SQLite считывает вашу запись базы данных в память, она читает всю запись и все страницы, которые она занимает. Поэтому, если ваша запись содержит BLOB, она может занимать много страниц, и вы будете извлекать существующие страницы из кэша и заменять их страницами своей записи BLOB.

Это не так уж плохо, если вы просто просматриваете и загружаете все свои BLOB-объекты, чтобы что-то с ними сделать (например, отобразите их). Но если, скажем, вы сделали запрос, в котором вы просто хотели получить некоторые данные, которые находятся в той же строке, что и BLOB, этот запрос был бы намного медленнее, чем если бы запись не содержала большой BLOB.

Так что, как минимум, вы должны хранить данные BLOB в отдельной таблице. Например:

CREATE TABLE blobs ( id INTEGER PRIMARY KEY, data BLOB );
CREATE TABLE photos ( id INTEGER PRIMARY KEY, name TEXT, blob_id INTEGER, 
    FOREIGN KEY(blob_id) REFERENCES blobs(id) );

Или, что еще лучше, храните данные BLOB в виде файлов вне базы данных SQLite.

Обратите внимание, что можно изменить размер кэша страницы с помощью операторов SQL PRAGMA (если вы не используете CoreData).

9 голосов
/ 13 марта 2009

Одним из вариантов (и обычно предпочтительным при работе в SQL) является запись изображения в файл в системе и сохранение пути (или некоторого другого вида идентификатора) в базе данных.

2 голосов
/ 29 января 2010

Запись изображения в базу данных SQLite

if(myImage != nil){
    NSData *imgData = UIImagePNGRepresentation(myImage);
    sqlite3_bind_blob(update_stmtement, 6, [imgData bytes], [imgData length], NULL);    
    }
    else {
        sqlite3_bind_blob(update_stmtement, 6, nil, -1, NULL);
    }

Чтение из базы данных SQLite:

NSData *data = [[NSData alloc] initWithBytes:sqlite3_column_blob(init_statement, 6) length:sqlite3_column_bytes(init_statement, 6)];
        if(data == nil)
            NSLog(@"No image found.");
        else
            self.pictureImage = [UIImage imageWithData:data];   
0 голосов
/ 27 мая 2015

Вы должны сначала написать изображение в файловой системе. а затем возьмите путь к изображению и сохраните этот путь к изображению (URL) как TEXT в sqlite.

0 голосов
/ 05 июля 2012

Лучше всего сжимать изображение и сохранять его в базе данных или файловой системе. Если вам не важно разрешение изображения, вы можете изменить размер изображения, используя:

   UIGraphicsBeginImageContext(newSize);  
   [image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];   
   UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();    
   UIGraphicsEndImageContext();

После этого вы можете использовать UIImageJPEGRepresentation для изображений JPEG со значением «0» для максимального сжатия. Или вы можете использовать UIImagePNGRepresentation для изображений PNG

...