Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Optener un Stream como "Result" en una funcion (https://www.clubdelphi.com/foros/showthread.php?t=16343)

sitrico 24-11-2004 17:39:24

Optener un Stream como "Result" en una funcion
 
Buenas:

Estoy mejorando una aplicación y se me ocurrio usar Streams en lugar de archivos temporales pero no he podido "pasar" el resultado de una funcion como un stream.

El caso es el siguiente:

Tengo una aplicacion que usa campos memo para almacenar archivos html (comprimidos) (En el registro 1 guardo los encabezados, y en los siguientes los diferentes contenidos, lo trabajé así para ahorrar espacio ya que como los html son generados desde winword los encabezados de los archivos eran identicos y muy, MUY grandes) entonces para poder usar el archivo html completo uso:

Código Delphi [-]
FiltrarTextos(db,Encabezados,Codigo,IdLibro);  
// Toma el Registro 1 + el que me interesa
Html         :=  TMemoryStream.Create;
InputStream  := TMemoryStream.Create;
OutputStream := TMemoryStream.Create;
Temp         := TMemoryStream.Create;
db.First;
While Not(db.Eof) do
   Begin
   InputStream.Clear;
   OutputStream.Clear;
   Temp.Clear;
   TBlobField(db.FieldByName('Data')).SaveToStream(Temp);
   InputStream.LoadFromStream(temp);
   If InputStream.Size <> 0 Then
      Begin
      ZDecompressStream(InputStream,OutputStream); // estan comprimidos
      Html.CopyFrom(OutputStream,0);
      End;
   db.Next;
   End;
html.SaveToFile(Destino);
Temp.Free;
OutputStream.Free;
InputStream.Free;
html.Free;

Como pueden ver eso me deja con un archivo temporal (destino)
Que cargo en un componente WebBrowser: TEmbeddedWB que permite usar:

WebBrowser.LoadFromFile(Destino);

Pero revizandolo un poco más tambien permite cargarlo desde:

WebBrowser.LoadFromStream(Destino);

Lo que quisiera hacer es convertir el procedimiento anterior en una funcion donde al final poga algo como:

Código Delphi [-]
Function CargarStreamHTML:TMemoryStream;

Begin
// Mismo codigo de antes para leer y descomprimir
// pero en lugar de:
// html.SaveToFile(Destino);
// Usar
Result := html;
End;

He hecho algunas pruebas y he tenido problemas con los create's y Free's ya que al final no sé si debo liberar el objeto asignado al result o si tengo que crear un objeto para asignarle el resultado.

En fin lo que necesito es un ejemplo de una funcion en la que el resultado pueda ir directo a un método "LoadFromStream".

Gracias

Uso delphi 7 + el TEmbeddedWB (http://www.euromind.com/iedelphi/embeddedwb.htm)

Toda la aplicación corre localmente y se usa para consultar unos informes históricos

roman 24-11-2004 18:35:55

Puedes regresar directamente como lo haces

Código Delphi [-]
Result := html;

pero no puedes liberarlo dentro de la misma función sino posteriormente. Por tanto, si usas simplemente:


Código Delphi [-]
LoadFromStream(CargarStream);

tendrás una fuga de memoria ya que no tienes ninguna referencia al Stream devuelto para poder liberarlo, así que tendrías que hacer algo como:


Código Delphi [-]
var
  Stream: TStream;

begin
  Stream := CargarStream;
  LoadFromStream(Stream);
  Stream.Free;
end;

de manera que no ahorras nada.

Si de plano te da flojera escribir tanto :D podrías englobar el stream dentro de una interfaz:

Código Delphi [-]
type
  ILazyStream = interface
    function GetStream: TMemoryStream;
    property Stream:  TMemoryStream read GetStream;
  end;

  TLazyStream = class(TInterfacedObject, ILazyStream)
  private
    FStream: TMemoryStream;

  public
    constructor Create;
    destructor Destroy; override;

    { ILazyStream }
    function GetStream: TMemoryStream;
  end;

...

constructor TLazyStream.Create(AStream: TMemoryStream);
begin
  inherited;
  FStream := TMemoryStream.Create;
end;

destructor TLazyStream.Destroy;
begin
  FStream.Free;
  inherited;
end;

function TLazyStream.GetStream: TMemoryStream;
begin
  Result := FStream;
end;

En tu función CargarStream creas una instancia de TLazyStream y esa es la que devuelves usando LazyStream.Stream:

Código Delphi [-]
function CargarStream: ILazyStream;
begin
  Result := TLazyStream.Create;

  ...
end;

...

LoadFromStream(CargarStream.Stream);

Así, cuando se pierda el contexto de LoadFromStream (es decir termine el procedimiento desde donde lo llamas) CargarStream, siendo una interfaz, automáticamente llamará al destructor de TLazyStream.

// Saludos

sitrico 24-11-2004 19:14:15

Bueno Gracias (aunque la parte del interface escapa de mis posibilidades actuales :( ) creo que has dado en el clavo.

Por suerte, el trabajo de crear los html lo realizo dentro de un objeto:

Código Delphi [-]
Type
TGenHTML = class(TObject)
  Private
  Public
    Procedure   FiltrarTextos(db:TDataSet;Encabezados:Integer;Codigo: String;IdLibro:Integer);
    Function    GetURL(db:TDataSet;Encabezados:Integer;Codigo,Destino:String;IdLibro:Integer): String;
    Function    GetText(db:TDataSet;Codigo:String): String;
    Procedure   ResaltarBusqueda(f,ElTextoBuscado: String);
    Procedure   ComprimirHtml(db:TDataSet;Origen:String);
   End;

Ahora se me ocurre que puedo cambiar el objeto padre de TObject a TMemoryStream (que cuenta con los Métodos LoadFromStream y LoadFromFile (y los save...) entonces lo unico que tendría que hacer es modificar las rutinas para que en lugar de terminar creando un archivo temporal cargen el stream en el propio objeto derivado de TMemoryStream y no tendría que usar una función para obtener el resultado sino que mi objeto TGenHTML seria un "TStreamGenHTML"

Voy a probar a ver que sale. Gracias nuevamente.

sitrico 24-11-2004 22:06:38

Bueno, quedo muy bien, al convertir el objeto a un tMemoryStream lo único que tuve que hacer fue asignar el resultado a la variable "Self" y listo

Puedo usar:

Código Delphi [-]
Var
html : THTMLdbStream;
Begin
html := THTMLdbStream.Create;
Try
   html.LoadFromDB(Table1,0,'A0100102',1);
   EmbeddedWB1.LoadFromStream(html);
Finally
   html.free;
   End;
end;

Pero y siempre hay un pero. El componente tEmbeddedWB recibe el archivo html y lo muestra como texto (el código html) aparece:

<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns........

En lugar del archivo formateado.

Pienso que el problema puede estar en el largo de la línea (algunas de mucho más de 256 carácteres) o bien en el primer caracter del stream (distinto a "<") como puedo "Ver" y editar el contenido de un MemoryStream?

Ya he probado casí todo y por lo visto el problema es del tEmbeddedWB voy a buscar otras opciones y si acaso luego pondré otro post.


La franja horaria es GMT +2. Ahora son las 06:50:31.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi