C++Builder
  Начало   Форум   Помощь Войти Регистрация  
Страниц: [1] 2 3   Вниз
  Печать  
Автор Тема: Хранение файлов в БД  (Прочитано 43662 раз)
Kuks
Давний друг
**

Сказали спасибо: +0/-0
Offline Offline

Сообщений: 54


« : 22 сентября 2009, 09:39:41 »

Вопрос вечный как мир. Имеем - платформа Windows, MSSQL.
Принято решение, при хранении файлов - на сервере БД хранить ссылки на них, сами
файлы в файловой системе.
Возникает вопрос, при отправке файла со стороны клиента, как это организовать?
Не хочется делать шару на сервере, даже спрятанную $, тогда как передать
файл в папку сервера со стороны клиента?
Записан
Lilo
Участник
**

Сказали спасибо: +17/-6
Offline Offline

Сообщений: 253


« Ответ #1 : 22 сентября 2009, 09:49:09 »

...
Не хочется делать шару на сервере, даже спрятанную $, тогда как передать
файл в папку сервера со стороны клиента?

Вы сами поняли что спросили??
Записан
IT-IR
Участник
**

Сказали спасибо: +72/-22
Offline Offline

Сообщений: 877

Плата за вход-Разум!


« Ответ #2 : 22 сентября 2009, 09:50:32 »

вообще то считаю что лучше хранить данные в БД
если уж савсем так надо, то отправляешь данные в БД,  а уже СУБД сохраняет файл у себя где-то в шаре,

не знаю имеет ли MS SQL сохранять данные типа blob в папку сервера, но знаю что можно запустить какой-либо exe файл, и в параметрах его передать ID записи, по значению которого можно найти  данное поле (файл), далее, при успешной отработке этого exe ( файла возвращает 0),  значит можно удалить это поле с сервера, в другом варианте отработать возможные варианты
Записан
Kuks
Давний друг
**

Сказали спасибо: +0/-0
Offline Offline

Сообщений: 54


« Ответ #3 : 22 сентября 2009, 10:01:26 »

...
Не хочется делать шару на сервере, даже спрятанную $, тогда как передать
файл в папку сервера со стороны клиента?

Вы сами поняли что спросили??

Кто в теме, тот понял.
Записан
Kuks
Давний друг
**

Сказали спасибо: +0/-0
Offline Offline

Сообщений: 54


« Ответ #4 : 22 сентября 2009, 10:02:37 »

вообще то считаю что лучше хранить данные в БД
если уж савсем так надо, то отправляешь данные в БД,  а уже СУБД сохраняет файл у себя где-то в шаре,

не знаю имеет ли MS SQL сохранять данные типа blob в папку сервера, но знаю что можно запустить какой-либо exe файл, и в параметрах его передать ID записи, по значению которого можно найти  данное поле (файл), далее, при успешной отработке этого exe ( файла возвращает 0),  значит можно удалить это поле с сервера, в другом варианте отработать возможные варианты

Тоже так думал, но чет слишком сложно, у меня MSSQL2000, помоему он не может сохранять BLOB поля.
Записан
IT-IR
Участник
**

Сказали спасибо: +72/-22
Offline Offline

Сообщений: 877

Плата за вход-Разум!


« Ответ #5 : 22 сентября 2009, 10:51:45 »

ну тогда ничего не стоит написать консольное приложение которое будет делать это (в посте выше я это уже описывал)

Код
    INSERT ... //в таблицув кеоторая будет служить буфером, гд есть поле ID IDENTITY(1,1)
   DECLARE @id INT
   DECLARE @SaveExe VARCHAR(1000)
   DECLARE @RESULT INT    
SET @id = Scope_Identity()
 
   SET @SaveExe = 'SaveToPath -i' + CAST(@id AS VARCHAR) + ' -sc:\Share\' // где SaveToPath -  программа которая берет из таблицы blob  поле и сохраняет по  пути  которая служит вторым параметром
 
   set @result = master..xp_cmdshell @SaveExe, no_output
 
  if @result = 0
      delete
          Table
      where
           id = @id
 
Записан
oxotnik
Глобальный модератор
***

Сказали спасибо: +100/-15
Offline Offline

Сообщений: 2425


« Ответ #6 : 22 сентября 2009, 10:55:30 »

Тоже так думал, но чет слишком сложно, у меня MSSQL2000, помоему он не может сохранять BLOB поля.
2000-й прекрасно хранит двоичные данные в полях типа Image
Записан
Kuks
Давний друг
**

Сказали спасибо: +0/-0
Offline Offline

Сообщений: 54


« Ответ #7 : 22 сентября 2009, 10:56:58 »

Тоже так думал, но чет слишком сложно, у меня MSSQL2000, помоему он не может сохранять BLOB поля.
2000-й прекрасно хранит двоичные данные в полях типа Image

Согласен, а если файлы 50-60 Мб. Тормозов не будет?
Записан
IT-IR
Участник
**

Сказали спасибо: +72/-22
Offline Offline

Сообщений: 877

Плата за вход-Разум!


« Ответ #8 : 22 сентября 2009, 10:59:01 »

зависит от конфигурации сервера Строит глазки
ну и от реализации структуры (схемы) таблиц в которых ты будешь их хранить
Записан
oxotnik
Глобальный модератор
***

Сказали спасибо: +100/-15
Offline Offline

Сообщений: 2425


« Ответ #9 : 22 сентября 2009, 11:02:28 »

Согласен, а если файлы 50-60 Мб. Тормозов не будет?
Тормоза будут точно такие же как и при обычном копировании по сети
а если делать выборку, то в выбираемые поля не надо включать поле Image
т.е. вместо SELECT * FROM Table
надо
SELECT (все кроме Image) FROM Table и будет щастье
т.е. не надо зазря тягать все двоичные данные
ЗЫ: подобным образом реализовывал хранилище документации (вместе с видео и пр. мультимедией) ~50 юзеров и все довольно шустро работает
Записан
Kuks
Давний друг
**

Сказали спасибо: +0/-0
Offline Offline

Сообщений: 54


« Ответ #10 : 22 сентября 2009, 11:05:22 »

Спасибо, буду пробовать хранить в связанной с основной таблице
Записан
Kuks
Давний друг
**

Сказали спасибо: +0/-0
Offline Offline

Сообщений: 54


« Ответ #11 : 22 сентября 2009, 11:50:36 »

ЗЫ: подобным образом реализовывал хранилище документации (вместе с видео и пр. мультимедией) ~50 юзеров и все довольно шустро работает

А как если не секрет, реализовано открытие файла на клиенте?
Через создание временного файла или как?
Записан
oxotnik
Глобальный модератор
***

Сказали спасибо: +100/-15
Offline Offline

Сообщений: 2425


« Ответ #12 : 22 сентября 2009, 12:21:26 »

А как если не секрет, реализовано открытие файла на клиенте?
Через создание временного файла или как?
Документы хранились в виде хтмл страниц, поэтому пришлось через временные файлы делать (хотел протокол для IE реализовать чтоб напрямую из БД тянулись, но за ненадобностью не стал).
А вообще все зависит от задачи, можно создавать TBlobStream и напрямую из него читать
Записан
Kuks
Давний друг
**

Сказали спасибо: +0/-0
Offline Offline

Сообщений: 54


« Ответ #13 : 22 сентября 2009, 12:29:49 »

Попробую, отпишусь. Спасибо!
Записан
Kuks
Давний друг
**

Сказали спасибо: +0/-0
Offline Offline

Сообщений: 54


« Ответ #14 : 22 сентября 2009, 12:38:24 »

Не понял, сохраняю BLOB поле в Stream, например вордовский файл.
Как теперь его открыть в ворде без сохранения во временный файл?
Записан
IT-IR
Участник
**

Сказали спасибо: +72/-22
Offline Offline

Сообщений: 877

Плата за вход-Разум!


« Ответ #15 : 22 сентября 2009, 13:03:30 »

никак, всё зависит от того что ты хранишь и как выводишь, если хранишь рисунки, то бес проблем можно их через BlobStream в TImage засунуть, в твоем случае придется сохранять
Записан
oxotnik
Глобальный модератор
***

Сказали спасибо: +100/-15
Offline Offline

Сообщений: 2425


« Ответ #16 : 22 сентября 2009, 13:59:27 »

можно через вордовское OLE, но дюже геморно
можно открывать через TOleContainer::LoadFromStream (если не ошибаюсь)
Записан
Kuks
Давний друг
**

Сказали спасибо: +0/-0
Offline Offline

Сообщений: 54


« Ответ #17 : 24 сентября 2009, 16:01:55 »

Код
DWORD WINAPI SaveDocToFile (LPVOID ID)
{
       int id = (int)ID;
       AnsiString fn = "C:\\MyTemp\\" + FileTableForm->FTADODataSetFileName->AsString.Trim();
       TADOStoredProc *FileQuery = new TADOStoredProc(FileTableForm);
       FileQuery->Active = false;
       FileQuery->Connection = FileTableForm->FTADOConnection;
       FileQuery->ProcedureName = "GetFile;1";
       FileQuery->Parameters->CreateParameter("@No",ftInteger,pdInput,4,id);
       FileQuery->Active = true;
       TBlobField *FileQueryBody = (TBlobField*)FileQuery->FieldByName("File");
       FileQueryBody->SaveToFile(fn);
       FileQuery->Active = false;
       FileTableForm->FTProgressBar->Position = 100;
       delete FileQuery;
       return 0;
}

Сделал так, спасибо Oxotnik.

Тепер вопрос, как  отобразить процесс копирования файла, например в прогресс бар?
Записан
oxotnik
Глобальный модератор
***

Сказали спасибо: +100/-15
Offline Offline

Сообщений: 2425


« Ответ #18 : 24 сентября 2009, 16:56:42 »

Тепер вопрос, как  отобразить процесс копирования файла, например в прогресс бар?
копировать из потока в поток не стандартными средствами, а побайтно (килобайтно) и отображать уже этот свой процесс копирования
Записан
Kuks
Давний друг
**

Сказали спасибо: +0/-0
Offline Offline

Сообщений: 54


« Ответ #19 : 28 сентября 2009, 11:05:37 »

Чего то не могу вкурить, как это сделать. Копировать BLOB полу в Stream, а потом
писать эток поток побайтно в файл используя API?
Записан
oxotnik
Глобальный модератор
***

Сказали спасибо: +100/-15
Offline Offline

Сообщений: 2425


« Ответ #20 : 28 сентября 2009, 14:25:12 »

Код
TBlobStream *stm1 = // получаем поток из поля БД
TFileStream *stm2 = new TFileStream ("somefile.tmp");
char buf;
ProgressBar1->Max = stm1->Size;
for (long i = 0; i < stm1->Size; i++)
{
   stm1->Read(&buf, 1);
   stm2->Write(&buf, 1);
   ProgressBar1->Pos++;
}
 
Записан
Kuks
Давний друг
**

Сказали спасибо: +0/-0
Offline Offline

Сообщений: 54


« Ответ #21 : 28 сентября 2009, 15:47:11 »

Да я примерно так и предствлял, только как получить поток из поля БД напрямую?
Использую ADO. Я могу получить его в TBlobField, а потом SaveToStream, но это получается
двойная работа.
Записан
oxotnik
Глобальный модератор
***

Сказали спасибо: +100/-15
Offline Offline

Сообщений: 2425


« Ответ #22 : 28 сентября 2009, 16:27:33 »

The following example copies the data in the Notes field of Table1 to the Remarks field of ClientDataSet1.
Код
void __fastcall TForm1::Button1Click(TObject *Sender)
 
{
 TBlobStream *Stream1;
 TStream *Stream2;
 
 Stream1 = new TBlobStream(Table1Notes, bmRead);
 try
 {
   ClientDataSet1->Edit();
   // here’s another way to create a blob stream
   Stream2 = ClientDataSet1->CreateBlobStream(ClientDataSet1->FieldByName("Remarks"), bmReadWrite);
   try
   {
     Stream2->CopyFrom(Stream1, Stream1->Size);
     ClientDataSet1->Post();
   }
   __finally
   {
 
     delete Stream2;
   }
 }
 __finally
 {
   delete Stream1;
 }
}
Записан
Kuks
Давний друг
**

Сказали спасибо: +0/-0
Offline Offline

Сообщений: 54


« Ответ #23 : 28 сентября 2009, 16:46:09 »

Да я все это видел, пытался сделать так:

TBlobStream *BS = new TBlobStream((TBlobField*)FileQuery->FieldByName("File"),bmRead);

На что компилятор дает Undefined..... TBlobStream. Почему так, непонятно
Записан
IT-IR
Участник
**

Сказали спасибо: +72/-22
Offline Offline

Сообщений: 877

Плата за вход-Разум!


« Ответ #24 : 28 сентября 2009, 18:24:48 »

Да я все это видел, пытался сделать так:

TBlobStream *BS = new TBlobStream((TBlobField*)FileQuery->FieldByName("File"),bmRead);

На что компилятор дает Undefined..... TBlobStream. Почему так, непонятно

Код
 
#include "DB.hpp"
// взависимости от того что используете
#include "ADODB.hpp"
 
Записан
Kuks
Давний друг
**

Сказали спасибо: +0/-0
Offline Offline

Сообщений: 54


« Ответ #25 : 29 сентября 2009, 10:01:42 »

Спасибо за терпение, сделал.
Каким образом теперь знать об окончании выполнения функции потока?
Код
DWORD WINAPI SaveDocToFile (LPVOID ID)
{
       int id = (int)ID;
       AnsiString Buffer = 0;
       Char * buffer = 0;
       AnsiString fn = "C:\\MyTemp\\" + FileTableForm->FTADODataSetFileName->AsString.Trim();
       TADOStoredProc *FileQuery = new TADOStoredProc(FileTableForm);
       FileQuery->Active = false;
       FileQuery->Connection = FileTableForm->FTADOConnection;
       FileQuery->ProcedureName = "GetFile;1";
       FileQuery->Parameters->CreateParameter("@No",ftInteger,pdInput,4,id);
       FileQuery->Active = true;
       TADOBlobStream *BS = new TADOBlobStream((TBlobField*)FileQuery->FieldByName("File"),bmRead);
       TFileStream *FStream =  new TFileStream (fn,fmCreate);
       for (int i = 0; i < BS->Size; i++)
       {
               BS->Position = i;
               BS->Read(&Buffer,1);
               buffer = Buffer.c_str();
               FStream->Write(&buffer,1);
               FileTableForm->FTProgressBar->Position = 100 * i / BS->Size;
       }
       FileTableForm->FTProgressBar->Position = 0;
       FileQuery->Active = false;
       delete FileQuery;
       return 0;
Записан
IT-IR
Участник
**

Сказали спасибо: +72/-22
Offline Offline

Сообщений: 877

Плата за вход-Разум!


« Ответ #26 : 29 сентября 2009, 10:22:23 »

в таймере
Код
 
DWORD retcode;
if ( !GetExitCodeThread( ThreadHandle, &retcode ) )
{
cout << "GetExitCodeThread is NULL";
TimerThread->Enabled = false;
}
else if ( retcode != STILL_ACTIVE)
{
                       cout << "Thread is executed";
                       TimerThread->Enabled = false;
}
 

да и вооще на форуме про потоки информации куча
Записан
oxotnik
Глобальный модератор
***

Сказали спасибо: +100/-15
Offline Offline

Сообщений: 2425


« Ответ #27 : 29 сентября 2009, 10:37:39 »

Спасибо за терпение, сделал.
Каким образом теперь знать об окончании выполнения функции потока?
работать с компонентами напрямую из потока нельзя - рано или поздно вылезет ошибка, надо отправлять хендлу компонента сообщение (PostMessage) и таким же макаром сообщать основному потоку о завершении (предпоследней строкой в теле потока делать PostMessage(MainForm->Handle...) а в самой форме это как то обрабатывать)
Записан
Kuks
Давний друг
**

Сказали спасибо: +0/-0
Offline Offline

Сообщений: 54


« Ответ #28 : 29 сентября 2009, 14:33:56 »

Как тогда вообще из функции потока обращаться к компонентам?
Записан
oxotnik
Глобальный модератор
***

Сказали спасибо: +100/-15
Offline Offline

Сообщений: 2425


« Ответ #29 : 29 сентября 2009, 15:20:42 »

ну я же сцылку то дал на пример, посмотри, проникнись
Записан
Страниц: [1] 2 3   Вверх
  Печать  
 
Перейти в: