Russian Qt Forum

Qt => Базы данных => Тема начата: Danila_Bagrofff от Январь 02, 2011, 22:30



Название: Сохранить файл в блоб-поле БД MSSQL
Отправлено: Danila_Bagrofff от Январь 02, 2011, 22:30
Знаю, что записывать файлы в БД - не есть хорошо, но есть в этом необходимость.
Есть блоб-поле в БД MSSQL и путь до файла.
Как организовать запись данного файла в данное блоб-поле?...

Подскажите?.. не очень получается что-то...


Название: Re: Сохранить файл в блоб-поле БД MSSQL
Отправлено: merke от Январь 03, 2011, 12:28
Делал такое как то на VB 6. Не знаю как это сделать на Qt, не сталкивался ещё с этим. Могу подсказать алгоритм.
Если файл очень большой, то нужно считывать его в память кусками и писать в блоб-поле. Записывать нужно в бинарном виде. Если файл не очень большой, то можно сразу считать его всего в память и записать в блоб-поле.


Название: Re: Сохранить файл в блоб-поле БД MSSQL
Отправлено: Danila_Bagrofff от Январь 03, 2011, 12:44
да, файлы достаточно большие....

как это делать с одним insert'ом...?


Название: Re: Сохранить файл в блоб-поле БД MSSQL
Отправлено: merke от Январь 03, 2011, 12:49
Считать в QByteArray и загнять всё это в базу


Название: Re: Сохранить файл в блоб-поле БД MSSQL
Отправлено: Danila_Bagrofff от Январь 03, 2011, 17:29
Нет, именно интересно, как не читая весь файл, записать в бд... ведь инсерт один раз делается...

Или я что-то не понимаю?...


Название: Re: Сохранить файл в блоб-поле БД MSSQL
Отправлено: shirushizo от Январь 03, 2011, 17:58
Функцию пользуй и делай инсерт
Код:
QByteArray QIODevice::readAll ()

Нет, именно интересно, как не читая весь файл, записать в бд... ведь инсерт один раз делается...
Или я что-то не понимаю?...
Не читая весь файл?  :o Это как? Прочитал начало и конец, а середину пусть SQL сам выдумает?


Название: Re: Сохранить файл в блоб-поле БД MSSQL
Отправлено: alexman от Январь 03, 2011, 18:31
Код:
QByteArray QIODevice::readAll ()
А что будете делать, если содержимое файла в оперативку не влезает?


Название: Re: Сохранить файл в блоб-поле БД MSSQL
Отправлено: Danila_Bagrofff от Январь 04, 2011, 07:52
Вот именно интересует способ, как это сделать частями - в потоке, чтоб не забивать сильно оперативку - пусть чуть подольше, но менее грузно для оперативки...

Дайте совет, а народ?


Название: Re: Сохранить файл в блоб-поле БД MSSQL
Отправлено: Zmeishe от Январь 04, 2011, 09:49
Задача решается средствами SQL сервера, т.е. API функциями SQL сервера.

Для Interbase/Firebird я сам BLOB частями записывал.
Вот пример
Код:
// Старт транзакции
...
// Присвоение значений параметрам sql инструкции
...
// Если параметр имеет тип BLOB
ISC_LONG total_size; // Размер файла
ISC_LONG blob_segment_size = 1024 * 32;

// Создание BLOB
isc_create_blob2(status_vector, &db_handle, &tr_handle, &blob_handle, &blob_id, 0, NULL) );

while( total_size )
{
 if (total_size < blob_segment_size) blob_segment_size = total_size;

 // Чтение сегментов из файла и запись в BLOB
 ...
 isc_put_segment(status_vector, &blob_handle, blob_segment_size, blob_segment);
 
 total_size -= blob_segment_size;
}
// Закрытие BLOB
isc_close_blob(status_vector, &blob_handle);

// Выполнение SQL инструкции (insert/update)
...
// Подтверждение транзакции
...


Название: Re: Сохранить файл в блоб-поле БД MSSQL
Отправлено: ufna от Январь 04, 2011, 19:03
Считать частями - через QByteArray и QDataStream к примеру. В чемпроблема? В разделении на части?


Название: Re: Сохранить файл в блоб-поле БД MSSQL
Отправлено: Zmeishe от Январь 04, 2011, 20:00
Считать частями - через QByteArray и QDataStream к примеру. В чемпроблема? В разделении на части?

Проблема в sql драйверах. Все драйверы принимают значения параметров sql запроса "за раз".
А с точки зрения Qt драйвер принимает значения от модели.
Ты можешь считывать частями, но модель будет это накапливать. И только потом передаст драйверу. Драйвер серверу.

Если у тебя в BLOB`ах хранятся файлы документов или картинок, т.е. размером до 30Мб, то на общей производительности это мало отразится.
А если в BLOB запихивать видео файлы от 100Мб до Гигабайтов, то "за раз" не только кеша sql сервера не хватит, но и операционки может не хватить - свопить начнёт.  С производительностью можешь проститься.
Выход один - читать частями и в BLOB писать тоже частями, т.е. в обход Qt модели и SQL драйвера, что я, собственно, и показал на выжимке из своего кода.


Название: Re: Сохранить файл в блоб-поле БД MSSQL
Отправлено: Danila_Bagrofff от Январь 05, 2011, 15:07
А программно видимо никак?... у меня пока файлы до 100 метров...


Название: Re: Сохранить файл в блоб-поле БД MSSQL
Отправлено: twp от Январь 05, 2011, 17:15
RTMF http://www.databasejournal.com/features/mssql/article.php/3724556/Storing-Images-and-BLOB-files-in-SQL-Server-Part-2.htm (http://www.databasejournal.com/features/mssql/article.php/3724556/Storing-Images-and-BLOB-files-in-SQL-Server-Part-2.htm)


Название: Re: Сохранить файл в блоб-поле БД MSSQL
Отправлено: Zmeishe от Январь 05, 2011, 17:27
Цитата: Danila_Bagrofff
А программно видимо никак?... у меня пока файлы до 100 метров...

Тогда непонятно зачем этот вопрос был?
Нет, именно интересно, как не читая весь файл, записать в бд... ведь инсерт один раз делается...
Если не читая весь файл, значит частями. Теперь и частями тебе не подходит.

Ты думаешь мы тут стелепатять должны, что именно тебе нужно? Или у тебя пока мнения нет?


Название: Re: Сохранить файл в блоб-поле БД MSSQL
Отправлено: Danila_Bagrofff от Январь 09, 2011, 19:53
Все подходит, только это хотелось бы реализовать программными методами только c помощью qt.


Название: Re: Сохранить файл в блоб-поле БД MSSQL
Отправлено: twp от Январь 11, 2011, 11:56
А чем собственно не устроило то решение, что я кинул по ссылке? По ходу это то что нужно - нет прямой работы с файлами, а тем более разбитие их на части, все делается средствами СУБД + Qt как интерфейс. Чего не хватает?


Название: Re: Сохранить файл в блоб-поле БД MSSQL
Отправлено: Prm от Январь 11, 2011, 16:06
Опишу свою методику, она на 100% применима для данного случая. Единственное исключение - файл хранится в текстовом поле. Использую MySQL. В базе данных сохраняются *.pdf файлы некоторых отчетов. Данные храню в двух таблицах. Первая - описание параметров отчета, вторая - данные отчета (несколько записей на один файл, количество записей зависит от размера файла и размера поля). Содержимое файла хранится в текстовом  (шестнадцатеричном) виде. Структура таблиц следующая:
Код:
/*=============================================================================
                   Таблица имеющихся файлов
 =============================================================================*/
CREATE TABLE IF NOT EXISTS `files_info`
(
    `ID`                int(10) unsigned    NOT NULL AUTO_INCREMENT COMMENT 'Идентификатор записи',
    `CREATED`             datetime            DEFAULT NULL                COMMENT 'Время создания записи', 
    `USER_NAME`         TEXT                                                    COMMENT 'Оператор',
    `PROC_DATE`         datetime            DEFAULT NULL                COMMENT 'Дата поверки',
    `REP_NUMBER`        int(10) unsigned    NULL                          COMMENT 'Номер отчета', 
    PRIMARY KEY  (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET='UTF8' COMMENT='Таблица имеющихся файлов';

/*=============================================================================
                   Таблица данных(содержимого) файлов
 =============================================================================*/
CREATE TABLE IF NOT EXISTS `files_data`
(
    `ID`                  int(10) unsigned    NOT NULL AUTO_INCREMENT COMMENT 'Идентификатор записи',
    `FILE_ID`           int(10) unsigned    DEFAULT NULL                    COMMENT 'Идентификатор файла',   
    `DATA`              TEXT                                                         COMMENT 'Данные файла',
    PRIMARY KEY  (`ID`),
    CONSTRAINT `FK_4` FOREIGN KEY (`FILE_ID`) REFERENCES `files_info` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE

) ENGINE=InnoDB DEFAULT CHARSET='UTF8' COMMENT='Таблица данных файлов';

Алгоритм сохранения файла следующий:
1. Создаю запись о файле в таблице files_info, получаю ID записи
2. Частями считываю файл в бинарном виде, конвертирую в строку в шестнадцатеричном виде
3. Создаю запись с данными файла в таблице files_data, FILE_ID = идентификатор записи о файле
4. Повторить пп 2-3 пока файл не будет считан и сохранен в БД полностью

Почему использовано данное решение:
1. Работа с базой данных через хранимые процедуры
2. Использование функции MySQL LOAD_FILE(...) невозможно, т.к. клиент и сервер разные машины и нет возможности скопировать файл на сервер. Фунция LOAD_FILE(...) помещает в базу только файлы, расположенные на той же машине, на которой запущен сервер MySQL

Плюсы:
-малое расходование ресурсова

Минусы:
-требуется время на конвертирование данных файла