Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Varios (https://www.clubdelphi.com/foros/forumdisplay.php?f=11)
-   -   Algo extraño con TstringList (https://www.clubdelphi.com/foros/showthread.php?t=62307)

Cecilio 16-12-2008 10:14:34

Algo extraño con TstringList
 
Hola a todos.

He creado un pocedimiento que exporta tablas de Ib a ficheros de texto.

Los nombres de los campos los extraigo usando un TStringList.

pero al liberar el stringlist da un error:

Código Delphi [-]
  gs:=TstringList.Create;
  gs:=ibb.FieldList;
  s:='';
  for v:=0 to gs.Count-1 do
      s:=s+gs[v]+';';
  writeln(t,s);
  gs.free;
...
...
sigue el resto de código sin dar error.
end;

Lo curioso es que el método continua sin problemas y hace la exportación correctamente. Pero al finalizar el procedimiento da el error.

Si quito el gs.free ya no da error.

¿ es porqué pude ser ?

dec 16-12-2008 10:20:43

Hola,

Creo que hace falta un poco más de código. ¡Ah! Y el mensaje de error en cuestión...

Cecilio 16-12-2008 10:36:59

Esa es la parte que escribe la lista de nombres de campos. En el resto del código no se hace referencia a ese objeto, por eso lo libero nada más terminar.

De todas formas voy a poner el procedimiento completo.
Código Delphi [-]
procedure TForm1.Generico(tb: string);
var
   s: string;
   t: TextFile;
   n,v: integer;
   gs: TstringList;
   ibb: TIBquery;

begin

  AssignFile(t,destino.Text+tb+'.txt');
  rewrite(t);

 if not IBDatabase1.Connected then
  begin
    IBDatabase1.DatabaseName:=server.Text;
    ibDatabase1.Connected:=true;
  end;
  ibb:= TibQuery.Create(nil);
  ibb.Database:=Ibdatabase1;
  ibb.Transaction:=IbTransaction1;

  Ibb.SQL.Add('select * from '+tb);
  ibb.Open;
  ibb.First;
  ibb.Last;
  Progressbar1.Max:=Ibb.RecordCount;
  progressbar1.Position:=0;

  gs:=TstringList.Create;
  gs:=ibb.FieldList;
  s:='';
  for v:=0 to gs.Count-1 do
      s:=s+gs[v]+';';
  writeln(t,s);

  ibb.First;
  n:=0;
  while not ibb.Eof do
  begin

     s:='';
     for v:=0 to ibb.FieldCount-1 do
      s:=s+ibb.Fields.Fields[v].AsString+';';

     writeln(t,s);

     inc(n);
     progressbar1.Position:=n;
    ibb.Next;
  end;
closeFile(t);
ibb.Close;
ibb.Free;
//gs.Free;

end;
(en este, he probado a ponerlo al final y solo no da error cuando está comentado y no actua.)

El error es algo como: "Exeception class EAccessViolation with message "Access violation at adress 000000. Read of adress 000000. Proced stoped"
Lo genera el debuger, creo.

coso 16-12-2008 10:37:37

el error esta en que estas eliminando gb = ibb.fieldlist directamente. Puedes, o bien usar el assign

Código Delphi [-]
gs := TStringList.Create;
gs.Assign(ibb.FieldList)
....
gs.Free;

o bien trabajar directamente con ibb.FieldList, sin liberarlo

Cecilio 16-12-2008 10:42:12

¡¡¡ Efectivamente !!!

Ahora va genial. Por curiosidad. ¿ poqué funciona con Assign ?

Si de camino alquien quiere mejorar el código que he puesto mejor, así aprendo directamente de los maestros. :)

coso 16-12-2008 11:10:57

Uf, estoy muy muy liado, si no ya le echaba un vistazo. En cuanto al assign, cuando tu usas un igual, =, con objetos lo que verdaderamente estas haciendo es decir que la dirección de memoria de uno va a ser la misma que la del otro. Asi que lo que tu hacias era crear un objeto TStringList con cierta dirección de memoria, y luego en esa misma variable poner la dirección de memoria del ibb.FieldList (por lo que la otra se perdia en el limbo). Luego al llegar al free, lo que estabas liberando era ibb.FieldList mediante la variable gb. Assign lo que hace (y una consulta al f1 siempre va bien ;) ) es copiar todas las propiedades de un objeto a otro.

Caro 16-12-2008 13:54:41

[quote=Cecilio;331090Si de camino alquien quiere mejorar el código que he puesto mejor, así aprendo directamente de los maestros. :)[/quote]

Hola cecilio, la diferencia entre el Assign y el igual ya te lo ha explicado el amigo coso. También puedes utilizar el procedimiento GetFieldNames que te devuelve la lista de campos de tu DataSet en el TString que le pases como parametro y para grabar en tu archivo puedes hacerlo direcatmente con SaveToFile de tu StringList.

Tu codigo quedaría así mas o menos

Código Delphi [-]
procedure TForm1.Generico(tb: string);
var
   s: string;
   n,v: integer;
   slCampos, slDatos: TstringList;
   ibb: TIBquery;
begin
 if not IBDatabase1.Connected then
  begin
    IBDatabase1.DatabaseName:=server.Text;
    ibDatabase1.Connected:=true;
  end;
  ibb:= TibQuery.Create(nil);
  ibb.Database:=Ibdatabase1;
  ibb.Transaction:=IbTransaction1;

  Ibb.SQL.Add('select * from '+tb);
  ibb.Open;

  slCampos :=TstringList.Create;
  slDatos :=TstringList.Create;
 
Try
  ibb.First;
  ibb.Last;
  Progressbar1.Max:=Ibb.RecordCount;
  progressbar1.Position:=0;

  ibb.GetFieldNames(slCampos);

  s:='';
  for v:=0 to slCampos.Count-1 do
      s:=s+slCampos[v]+';';
  
  slDatos.Add(s);

  ibb.First;
  n:=0;
  while not ibb.Eof do
  begin

     s:='';
     for v:=0 to ibb.FieldCount-1 do
      s:=s+ibb.Fields.Fields[v].AsString+';';

     slDatos.Add(s);

     inc(n);
     progressbar1.Position:=n;
    ibb.Next;
  end;//While
  slDatos.SaveToFile('C:\file.txt');
Finally
 ibb.Close;
 ibb.Free;
 slCampos.Free;
 slDatos.Free;
end;//try
end;

Saluditos

Al González 16-12-2008 15:14:33

¡Hola!

Aquí hay otro ejemplo de cómo vaciar el contenido de un conjunto de datos a un CSV: http://www.youcantwin.com/dasblogce/...SaveToCsv.aspx

Se menciona a los Client Data Sets, pero la función sirve con cualquier otro tipo de conjunto de datos.

Pero, al igual que Linett, creo que yo también emplearía un TStringList y vaciaría el contenido a disco con el método SaveToFile, en lugar de usar las antiguas y entrañables funciones para manejo de archivos de Pascal.

Un vaciado abrazo.

Al González. :)

javier7ar 17-12-2008 01:59:41

Por si te sirve, podes usar un TClientDataSet, que tiene un metodo SaveToFile y te guarda todo en un XML con un solo metodo y no tenes que andar haciendo todo el laburo vos. Despues lo podes recuperar con el metodo LoadFromFile y lo levantas al TClientDataSet de nuevo. A menos que necesites que el archivo sea CSV, el XML con el TClientDataSet me parece la opcion mas facil.
Saludos

rgstuamigo 17-12-2008 20:28:20

Tengo una duda con respecto a error
 
Hola amigos ,leyendo este hilo se me quedo una duda y seria bueno que me lo pudieran aclarar ,la duda es en esta linea de codigo que puso el amigo Cecilio:

Código Delphi [-]
var
.
.
.
gs: TstringList;
..
.
.
.
gs:=TstringList.Create;//no seria necesario crearlo segun yo
gs:=ibb.FieldList;
.
.
.
gs.Free;//no hace falta liberarlo ya que es una referencia a bb.FieldList

Como podran verla variable gs no seria nesesario crearla(en este caso) sino darle solamente la asigancion que seria una referencia, lo que entiendo yo que hace el costructor Create es que reserva memoria para el objeto en si e inicializa sus atributos, pero en este caso ya para que crearlo si luego le voy a hacer una asignacion de otro objeto, no se si me explico, es algo asi como tener dos punteros apuntando a la misma direccion de memoria.
Esa es mi humilde opinion sobre el caso, si alguien tiene alguna objecion seria bueno para aclarar el asunto.;)
Saludos...:)

javier7ar 17-12-2008 20:33:28

claro, eso fue lo que le corrigieron en los primeros posts. El no se daba cuenta de eso, e incluso estaba teniendo un error por eso. Fijate que le dieron dos alternativas, una hacer un Assing (en ese caso si es necesario crearlo y liberarlo) y la otra usar directamente ibb.FieldList (ahi no necesitas ni la variable)
Saludos


La franja horaria es GMT +2. Ahora son las 09:26:02.

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