Добрый день!
Недавно встала задача загружать файлы документов в БД (поле 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 }
Комментариев нет:
Отправить комментарий