Добрый день!
Недавно встала задача загружать файлы документов в БД (поле BLOB) в виде OLE-объекта, которого в дальнейшем можно вывести в стандартный OLE контейнер Delphi для просмотра и последующего редактирования.
Первое что встает в голову воспользоватся стандартной функций OleContainer - CreateObjectFromFile.
т.е. сделать что то вроде такого кода
где TableData - это Blob-поле. Всем хорош данный код, но мне он не понравился по 2-м причинам:
1.нужно иметь OleContainer на форме
2.загрузка таким способом происходит довольно медленно, т.к. если OleContainer находится на форме, много времени тратится на лишнии операции (прорисовка и пр)
поэтому хотелось бы загружать файл документа сразу в БД минуя OleContainer, т.е создать внедренный Ole-объект на основе файла документа и поместить его в БД.
Вообщем повозившись полчасика родилось такое решение, которое по производительности обошло загрузку стандартным способом:
Недавно встала задача загружать файлы документов в БД (поле BLOB) в виде OLE-объекта, которого в дальнейшем можно вывести в стандартный OLE контейнер Delphi для просмотра и последующего редактирования.
Первое что встает в голову воспользоватся стандартной функций OleContainer - CreateObjectFromFile.
т.е. сделать что то вроде такого кода
Table.Append; try Stream := TMemoryStream.Create; OleContainer.CreateObjectFromFile(OpenDialog.FileName); OleContainer.SaveToStream(Stream); TableDATA.LoadFromStream(Stream); finally Stream.Free; end; Table.Post;
где TableData - это Blob-поле. Всем хорош данный код, но мне он не понравился по 2-м причинам:
1.нужно иметь OleContainer на форме
2.загрузка таким способом происходит довольно медленно, т.к. если OleContainer находится на форме, много времени тратится на лишнии операции (прорисовка и пр)
поэтому хотелось бы загружать файл документа сразу в БД минуя OleContainer, т.е создать внедренный Ole-объект на основе файла документа и поместить его в БД.
Вообщем повозившись полчасика родилось такое решение, которое по производительности обошло загрузку стандартным способом:
const StreamSignature = $434F4442; {'BDOC'} type TStreamHeader = record case Integer of 0: ( { New } Signature: Integer; DrawAspect: Integer; DataSize: Integer); 1: ( { Old } PartRect: TSmallRect); end; var ID : Integer; fDocOLE : TfDocOLE; FN : string; Stream : TMemoryStream; FStorage : IStorage; {Интерфейс хранилища} FOleObject: IOleObject; {Интерфейс является основным средством, с помощью которого внедренный объект наделяется базовой функциональностью, и взаимодействует с контейнером хранилища} FLockBytes: ILockBytes; {Интерфейс структурированного хранилища, который служит для доступа к длинным текстовым и двоичным данным} DataHandle: HGlobal; Buffer: Pointer; Header: TStreamHeader; begin if OpenDialog.Execute then begin FN := ExtractFileName(OpenDialog.FileName); FOleObject := nil; FStorage := nil; FLockBytes := nil; { Доступ к памяти для реализации ILockBytes } OleCheck(CreateILockBytesOnHGlobal(0, True, FLockBytes)); { Создание хранилища IStorage и связка его с реализацией интерфеса ILockBytes } OleCheck(StgCreateDocfileOnILockBytes(FLockBytes, STGM_READWRITE or STGM_SHARE_EXCLUSIVE or STGM_CREATE, 0, FStorage)); // Создание внедеренного объекта из файла OleCheck(OleCreateFromFile(GUID_NULL, PWideChar(OpenDialog.FileName), IOleObject, OLERENDER_NONE, nil, nil, FStorage, FOleObject)); OleCheck(GetHGlobalFromILockBytes(FLockBytes, DataHandle)); try { Создаем поток в памяти } Stream := TMemoryStream.Create; Stream.Position := 0; Header.Signature := StreamSignature; Header.DrawAspect := DVASPECT_CONTENT; { Контент } Header.DataSize := GlobalSize(DataHandle); // Записываем заголовок + контент Stream.WriteBuffer(Header, SizeOf(Header)); try Buffer := GlobalLock(DataHandle); // Записываем размер заголовка Stream.WriteBuffer(Buffer^, Header.DataSize); finally GlobalUnlock(DataHandle); end; Table.Append; Table NAME.Value := FN; Table DATA.LoadFromStream(Stream); Table.Post; finally Stream.Free; end; end; { OpenDialog }
Комментариев нет:
Отправить комментарий