Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2009.08.16;
Скачать: CL | DM;

Вниз

BLOB->OLEConrtainer->File?   Найти похожие ветки 

 
GRAND ©   (2009-06-18 14:36) [0]

Здравствуйте, уважаемые! :)

Вот такая вот палка о двух концах у меня приключилась. Вобщем, имеется некий набор документов, хранимый в BLOB-полях таблицы с деревянной структурой (FB 1.5). Документы довольно разнообразны - там и Word, и PDF, и TIF и еще может быть все, что угодно. Когда я пытался отобразить содержимое документа в OLEContainer, то вылетала ошибка "Invalid stream format". Ну, думаю, нас не проведешь, мы не сдадимся - выгрузил все документы в файлы, после чего заставил OLEContainer эти файлы перечитать и зашарабанить их в базу заново (т.е. получается, что OLEContainer хавает только то, что когда-либо проходило через его "руки"). Все получилось, красота - документы хранятся, в контейнере отображаются, казалось бы, о чем еще мечтать? Ан нет, нарисовалась-таки проблемка. Захотел дать пользователю возможность выгружать любой документ из базы в произвольно заданный файл - и вот тут-то она ему и сказала. Файл создается, но никак не открывается потом родной для него программой. Причем, заметил, что если файл изначально был в формате Word 97-2003, то все работает и открывается, а вот *.docx, *.xlsx (MS Office 2007) и особенно *.pdf (львиная доля всех документов!) ни в какую. Получается, что я могу одно из двух: либо тупо хранить документы в базе без какой-либо возможности превью либо с превью, но без экспорта. Подскажите пожалуйста, как победить? Я понимаю, что формат данных OLE-контейнера от формата исходного файла отличается, но как же его все-таки заставить сохранять файлы в их первозданном виде?

P.S. SaveToFile, SaveAsDocument - результат один и тот же.


 
Игорь Шевченко ©   (2009-06-18 14:46) [1]

Знакомый вопрос :)

Blob save to stream не помогает ?


 
GRAND ©   (2009-06-18 14:49) [2]


> Blob save to stream не помогает ?


Привет, Игорь! А какой смысл блоб сохранять в потоке, если содержимое в конечном итоге нужно выплюнуть в файл (корректный файл)? Ну TMemoryStream, допустим, позволит сохранить себя в файле, но формат-то этого файла будет все равно не тот, который нужен.


 
Andy BitOff ©   (2009-06-18 14:51) [3]


> GRAND ©   (18.06.09 14:49) [2]
> но формат-то этого файла будет все равно не тот, который нужен

Это почему? Уже проверил?


 
GRAND ©   (2009-06-18 14:53) [4]

Да, уже проверил.


 
Игорь Шевченко ©   (2009-06-18 14:56) [5]

GRAND ©   (18.06.09 14:49) [2]

Привет, Володя!

Почему не тот формат ? FB у меня сейчас нету, а в оракле я тебе могу пример набросать :)


 
GRAND ©   (2009-06-18 15:00) [6]


> Почему не тот формат ? FB у меня сейчас нету, а в оракле
> я тебе могу пример набросать :)


Вообще-то оно абсолютно фиолетово, в какой базе это все хранится, и FB тут не при чем. Вопрос заключается в отличии форматов Ole-контейнера, потока и исходного файла. Если файл затянуть в блоб as is, то он не покажется в контейнере (превью не будет), а если протащить его через жернова контейнера, то его формат изменится! И потом выкинутые из блоба снова в файл данные уже бесполезны, т.к. не открываются. Поэтому, Игорь, если ты сможешь набросать примерчик, где все то, что нужно, будет работать хоть в Оракле, хоть в Постгре, то буду тебе очень благодарен!


 
GRAND ©   (2009-06-18 15:03) [7]

Вот так файл затягивается в базу через контейнер:

 Var
   St : TStream;
begin
 St:=DM.tbClDocs.CreateBlobStream(DM.tbClDocsCD_BODY,bmReadWrite);
 If OpenDialog1.Execute Then
   Begin
     cxButtonEdit1.Text:=OpenDialog1.FileName;
     Screen.Cursor:=crHourGlass;
     If Not (DM.tbClDocs.State In [dsInsert, dsEdit]) Then DM.tbClDocs.Edit;
     OLEContainer1.CreateObjectFromFile(OpenDialog1.FileName,False);
     OLEContainer1.SaveToStream(St);
     DM.tbClDocsCD_STATE.AsInteger:=1;
     DM.tbClDocsCD_EXT.AsString:=ExtractFileExt(OpenDialog1.FileName);
     Screen.Cursor:=crDefault
   End;
 St.Free
end;


OLEContainer1.SaveToStream(St) - это одновременно и сохранение файла в блоб. Далее, уже за пределами этого обработчика, производится Post и вуа-ля.


 
Игорь Шевченко ©   (2009-06-18 16:23) [8]

Насчет примера - у меня не получается загрузить файл в OleContainer, причем, даже в примере из Demos - приложение висит. Оказывается, проблема известная и на experts-exchange не решенная.

Сам пример:
1. Таблица в базе:
CREATE TABLE files_data (
 name VARCHAR2(40) NOT NULL,
 data BLOB,
 CONSTRAINT files_data_pk PRIMARY KEY(name) USING INDEX TABLESPACE hs_idx
) TABLESPACE hs_dat
/


2. Главная форма

unit main;

interface
uses
 Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
 Dialogs, Menus, Grids, DBGridEh, OleCtnrs;

type
 TfMain = class(TForm)
   MainMenu1: TMainMenu;
   File1: TMenuItem;
   Open1: TMenuItem;
   Saveas1: TMenuItem;
   Preview1: TMenuItem;
   N1: TMenuItem;
   Exit1: TMenuItem;
   Grid: TDBGridEh;
   OpenDialog1: TOpenDialog;
   SaveDialog1: TSaveDialog;
   OleContainer1: TOleContainer;
   procedure Exit1Click(Sender: TObject);
   procedure FormShow(Sender: TObject);
   procedure Open1Click(Sender: TObject);
   procedure Saveas1Click(Sender: TObject);
   procedure Preview1Click(Sender: TObject);
   procedure OleContainer1Activate(Sender: TObject);
 end;

var
 fMain: TfMain;

implementation
uses
 data;

{$R *.dfm}

procedure TfMain.Exit1Click(Sender: TObject);
begin
 Close;
end;

procedure TfMain.FormShow(Sender: TObject);
begin
 OleContainer1.Visible := false;
 Grid.DataSource := dm.dsData;
end;

procedure TfMain.OleContainer1Activate(Sender: TObject);
begin
 OleContainer1.Modified := True;
end;

procedure TfMain.Open1Click(Sender: TObject);
begin
 with OpenDialog1 do
   if Execute then
     dm.LoadFile(FileName);
end;

procedure TfMain.Preview1Click(Sender: TObject);
begin
 with OpenDialog1 do
 if Execute then
 begin
   OLEContainer1.CreateObjectFromFile(dm.GetSavedTempFileName, false);
   OleContainer1.Visible := true;
 end;
end;

procedure TfMain.Saveas1Click(Sender: TObject);
begin
 with SaveDialog1 do
 begin
   FileName := Grid.DataSource.DataSet.FieldByName("name").AsString;
   if Execute then
     dm.SaveFile(FileName);
 end;
end;

end.


датамодуль:

unit data;

interface
uses
 SysUtils, Classes, DB, hsOraCursor, hsOraDataSet, hsOraDatabase;

type
 Tdm = class(TDataModule)
   db: ThsOraDatabase;
   qData: ThsOraDataSet;
   qDataNAME: TStringField;
   qDataDATA: TOraMemoField;
   dsData: TDataSource;
   qInsert: ThsOraDataSet;
   qUpdateBlob: ThsOraDataSet;
   procedure DataModuleCreate(Sender: TObject);
 public
   procedure LoadFile (const FileName: string);
   procedure SaveFile (const FileName: string);
   function GetSavedTempFileName: string;
 end;

var
 dm: Tdm;

implementation
uses
 Windows;

{$R *.dfm}

procedure Tdm.DataModuleCreate(Sender: TObject);
begin
 db.Open;
 qData.Open;
end;

function Tdm.GetSavedTempFileName: string;
var
 L: Integer;
 F: TFileStream;
begin
 Setlength(Result, MAX_PATH);
 L := GetTempPath(MAX_PATH, PChar(Result));
 if L > 0 then
 begin
   SetLength(Result, L);
   Result := IncludeTrailingPathDelimiter(Result) +
     qData.FieldByName("name").AsString;
   F := TFileStream.Create(Result, fmCreate);
   try
     TBlobField(qData.FieldByName("data")).SaveToStream(F);
   finally
     F.Free;
   end;
 end;
end;

procedure Tdm.LoadFile(const FileName: string);
var
 F: TFileStream;
 N, E: string;
begin
 E := ExtractFileExt(FileName); //. тъы■ўхэр
 N := Copy(ChangeFileExt(ExtractFileName(FileName), ""), 1, 40-Length(E))+E;
 qInsert.ParamByName("name").AsString := N;
 qInsert.ExecSQL;
 F := TFileStream.Create(FileName, fmOpenRead);
 try
   qUpdateBlob.ParamByName("name").AsString := N;
   qUpdateBlob.ParamByName("data").LoadFromStream(F, ftBlob);
   qUpdateBlob.ExecSQL;
   db.Commit;
   qData.Close;
   qData.Open;
 finally
   F.Free;
 end;
end;

procedure Tdm.SaveFile(const FileName: string);
var
 F: TFileStream;
begin
 F := TFileStream.Create(FileName, fmCreate);
 try
   TBlobField(qData.FieldByName("data")).SaveToStream(F);
 finally
   F.Free;
 end;
end;

end.


запросы:

qData.SQL - "SELECT name,data FROM files_data ORDER BY name"
qInsert.SQL - "INSERT INTO files_data (name) VALUES (:name)"
qUpdateBlob.SQL - "UPDATE files_data SET data = :data WHERE name = :name
                         RETURNING data INTO :data"

Сохраненный файл до бита идентичен загруженному


 
GRAND ©   (2009-06-19 10:05) [9]

Игорь, спасибо тебе большое за проделанную работу! Вчера не смог отреагировать, т.к. был срочно выдернут на совещание, продлившееся до глубокого вечера. Сегодня попробовал действовать по твоей схеме и напоролся на проблему с OLEContainer, которую уже проходил ранее. Проблема вот в чем: при организации превью файл через TFileStream создается, он железно лежит там, где ему и положено лежать, своей родной программой открывается, но при попытке грузануть его в контейнер через CreateObjectFromFile вылетает EOleSysError: "Не удается найте %1". Что это за хрень, я не знаю, предположил только лишь, что это чем-то похоже на запуск чего-то с параметром (как в bat"ах пишут, помнишь? %1 %2...). Вот как с этим быть? У тебя контейнер все показывает и ничего эдакого не выдает?


 
Игорь Шевченко ©   (2009-06-19 10:37) [10]

GRAND ©   (19.06.09 10:05) [9]

Володя, у меня не получается вообще загрузить файл в контейнер :) Никакой, хоть с диска, хоть из базы.

ситуация аналогичная

http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_23747098.html


 
GRAND ©   (2009-06-19 10:58) [11]


> Володя, у меня не получается вообще загрузить файл в контейнер
> :) Никакой, хоть с диска, хоть из базы.


Вон, выше я привел код, где файл грузится в контейнер :)


 
GRAND ©   (2009-06-19 11:03) [12]

Наверное придется-таки грузить файл в 2 блоба - один будет хранить его в олешном виде, а другой в исходном.  ППЦ!!! :)))


 
GRAND ©   (2009-06-19 11:11) [13]

Еще глюк: иногда при попытке открыть филе из контейнера (по дабл-клику) вылазит ошибка "Не удается открыть файл при помощи специального имени". Это еще че, блин, такое?


 
Игорь Шевченко ©   (2009-06-19 11:32) [14]

GRAND ©   (19.06.09 10:58) [11]

Ты ссылку-то прочитай :)


 
GRAND ©   (2009-06-19 11:55) [15]


> Ты ссылку-то прочитай :)


Ну и? Беру спокойно pdf (не MS Office, правда?), гружу и вижу его в контейнере!


 
Игорь Шевченко ©   (2009-06-19 12:13) [16]

GRAND ©   (19.06.09 11:55) [15]

А я не вижу, я зависаю. Об чем написано в ссылке "on some pc"

Потому не могу тебя проконсультировать по поведению OleContainer. Я знаю, что выгруженный из базы в моем примере файл идентичен загруженному (сравнивалось по fc /b), чего тебе тоже рекомендую - сравнить, что выходит из OleContainer, то, что сохраняется твоей выгрузкой из базы и то, что загружается в базу.


 
GRAND ©   (2009-06-19 12:57) [17]


> А я не вижу, я зависаю. Об чем написано в ссылке "on some
> pc"


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


 
Игорь Шевченко ©   (2009-06-19 13:06) [18]

GRAND ©   (19.06.09 12:57) [17]

Я висну даже на примере из Demos


 
GRAND ©   (2009-06-19 14:20) [19]

Как все запущено! :)

Ну, а у меня наконец-то все заработало, ура! Теперь вот чешу репу, возможен ли в контейнере мультистраничный просмотр или ну его на фиг?



Страницы: 1 вся ветка

Текущий архив: 2009.08.16;
Скачать: CL | DM;

Наверх




Память: 0.53 MB
Время: 0.019 c
6-1204874743
Михаил (Питер)
2008-03-07 10:25
2009.08.16
Широковещательный UDP запрос


15-1245011026
DillerXX
2009-06-15 00:23
2009.08.16
Лексикографическая сортировка?!


2-1245401116
Nil
2009-06-19 12:45
2009.08.16
как проверить наличие свойства компонента


2-1245577497
Bred
2009-06-21 13:44
2009.08.16
Цвет шрифта при использовании TextOut


15-1245060523
desc
2009-06-15 14:08
2009.08.16
PostgreSQL 8.3