Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Tablas planas (https://www.clubdelphi.com/foros/forumdisplay.php?f=20)
-   -   Estructura para Tabla paradox (https://www.clubdelphi.com/foros/showthread.php?t=86514)

tarco35 25-08-2014 01:50:46

Estructura para Tabla paradox
 
Hola, tengo la siguiente estructura:
Código Delphi [-]
Type
  RegGrafica = Record
                      Valores : Array [0..64,0..1500] Of Real;
                      Numero_Valores : Array [0..64] Of Integer; // numero de datos en cada serie
                      NumeroLectura : LongInt;
                    End;

y tengo que manejar un fichero con esa estructura, con sus correspondientes operaciones de inserción, modificación,....
el caso es que cuando va teniendo un numero considerable de registros se hace "eterno" el tiempo, ya que hago busquedas secuenciales en el archivo de disco y en caso de tener que modificar creo un fichero temporal, copiar los registros, borrar el fichero original y renombrar el fichero copia al nombre original.

Estoy usando delphi 6 y paradox
El caso es que no se me ocurre una estructura para una (o mas) tablas..... EL objetivo es cargar (o modificar o grabar) cada una de las 65 graficas con los valores indicados en el array "Valores" con un total de puntos indicados en "Numero_Valores", siendo "NumeroLectura" el dato que sirve de indice.

A alguien se le ocurre algo...
Gracias por su tiempo.

ecfisa 25-08-2014 03:00:02

Hola tarco35.

No me queda del todo claro el uso que vas a hacer de los datos ni como van a ser accedidos, pero en principio una tabla es un arreglo bidimensional.
Para el caso de "Valores" seguramente te sea mas fácil invertir la definición del arreglo, es decir declarar una tabla de 64 columnas por 1500 (o mas filas).
Código:

ID  | campo 1 | ... | campo 64
-----+---------+-----+---------
1    | valor 1 | ... | valor 64
...  | valor 1 | ... | valor 64
...  | valor 1 | ... | valor 64
1500 | valor 1 | ... | valor 64

Del mismo modo el arreglo "Numero_Valores" puede ser representado en una tabla con una (o dos) columnas y 64 (o más) filas.
Código:

ID  | campo 1
-----+--------
1    | valor 1
...  | ...
64  | valor 64

Pero habría que conocer mas a fondo la cuestión para asegurar que esta opción es la adecuada. Así como también el mejor modo de implementar inserciones, modificaciones y búsquedas acordes al caso.

Saludos :)

tarco35 25-08-2014 11:15:37

A ver si ahora me explico mejor....

La estructura lo que tiene que guardar son los valores que ha tomado una grafica con 1500 puntos como maximo (de media se leen sobre 500 o 600) y hay 64 graficas (normalmente se leen 50) tambien como maximo.... aunque no siempre hay los 1500 puntos y/o las 64 graficas.
La idea es guardar esos valores para despues poder cargarlos y representar la grafica de nuevo, o modificar los valores de la grafica y guardarlos de nuevo.

Estaba pensando en guardar el numero de grafica en un campo y todos los valores en uno de tipo MEMO (o asi) separados por algun delimitador y despues por codigo ir separando los valores, convertirlos a numero y meterlos en su sitio correspondiente.

ID_Lectura NumeroGrafica MemoValores

Gracias por su respuesta y su dedicacion. Un saludo

ecfisa 25-08-2014 19:50:48

Hola.

Ahora creo entender mejor la situación.

Si, también podrías guardar los valores separados por delimitadores en un campo BLOB. Pero tomá en cuenta que en ese caso, tenes que adicionar el tiempo empleado para la componer los datos antes del guardado y el necesario para la recomposición de los valores luego de la lectura. No sé si aportará mejorías en el caso de las lecturas secuenciales...

¿ En este momento estas usando un archivo de acceso aleatorio ?

Saludos :)

tarco35 25-08-2014 20:46:59

En este momento uso un archivo secuencial, por lo que el tiempo de acceso cada vez ira a peor, por eso es ver convertilo en una tabla de paradox.
He probado el tiempo que tardaria en meter todos los datos en el campo y usa del orden de 10/12 eternos segundos.... si no me queda otra, lo que haré es sacar un mensaje en pantalla con alguna animación para que el usuario vea que el sistema esta ocupado guardando los datos....

Gracias.

ecfisa 25-08-2014 21:31:10

Hola tarco35.

Una opción que te puede servir es usar archivos de acceso aleatorio, por ejemplo:
Código Delphi [-]
type
 TRegGrafica = packed record
  Valores : array [0..64,0..1500] of Real;
  Numero_Valores : array [0..64] of Integer;
  NumeroLectura : LongInt;
 end;
 TFileRegGrafica = file of TRegGrafica;

var
  Reg: TRegGrafica;
  FileReg: TFileRegGrafica;
Este tipo de tratamiento, te permite acceder de forma directa, tanto en lectura como en escritura, a los registros en disco:
Código Delphi [-]
  Seek(FileReg, 15); // posicion 15
  Read(FileReg, Reg); // o Write(FileReg, Reg);

Es más, gracias a un pequeño truco con moldeos podes usar un arreglo de registros para acceder a bloques de registros en un sólo acceso a disco:
Código Delphi [-]
var
  VecRec: array[0..50] of TRegGrafica;
begin
  (* se supone que el arreglo tiene los datos *)

  // guarda 50 registros en un solo acceso a disco
  BlockWrite(file(FileReg), Reg, 49); 

  // lee los primeros 50 registros en un solo acceso a disco
  Seek(FileReg, 0);
  BlockRead(file(FileReg), Reg, 49);
Y dado que los accesos a disco son una de las taréas más lentas, brinda una gran ganancia de velocidad. Una vez cargado el arreglo podes manejar todo desde memoria.

Si tenes dificultad para implementarlo, comentame y te preparo/adjunto un código demo.

Saludos :)

tarco35 26-08-2014 18:56:44

Muchas gracias.... lo probare y si no me sale bien ya te pregunto

un saludo

nlsgarcia 03-09-2014 23:45:13

tarco35,

Cita:

Empezado por ecfisa
...podes usar un arreglo de registros para acceder a bloques de registros en un sólo acceso a disco...

:rolleyes:

Revisa este código:
Código Delphi [-]
 unit Unit1;
 
 interface
 
 uses
   Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
   Dialogs, StdCtrls;
 
 type
   TForm1 = class(TForm)
     ListBox1: TListBox;
     Button1: TButton;
     Button2: TButton;
     Button3: TButton;
     Button4: TButton;
     procedure FormCreate(Sender: TObject);
     procedure Button1Click(Sender: TObject);
     procedure Button2Click(Sender: TObject);
     procedure Button3Click(Sender: TObject);
     procedure Button4Click(Sender: TObject);
   private
     { Private declarations }
   public
     { Public declarations }
   end;
 
   TData = record
      Name : Array[0..29] of Char;
      PIN : Integer;
      DateData : TDateTime;
   end;
 
 const
   CountReg = 1000;
 
 var
   Form1: TForm1;
   ArrayData : Array[0..CountReg-1] of TData;
   FileData : File of TData;
   FileName : String;
 
 implementation
 
 {$R *.dfm}
 
 // Inicializa la Aplicación
 procedure TForm1.FormCreate(Sender: TObject);
 begin
    Randomize;
    FileName := ExtractFilePath(Application.ExeName) + 'Data.txt';
 end;
 
 // Genera un Arreglo de Registros de 1000 Elementos
 procedure TForm1.Button1Click(Sender: TObject);
 var
    i : Integer;
 begin
    FillChar(ArrayData,Length(ArrayData),0);
    for i := 0 to CountReg - 1 do
    begin
       StrPCopy(ArrayData[i].Name,'Name-' + IntToStr(i));
       ArrayData[i].PIN := Random(1000);
       ArrayData[i].DateData := Now + Random(365);
    end;
 end;
 
 // Graba 1000 Registros en una Sola Operación de Acceso a Disco
 procedure TForm1.Button2Click(Sender: TObject);
 begin
    AssignFile(FileData, FileName);
    Rewrite(FileData);
    BlockWrite(FileData, ArrayData, CountReg);
    CloseFile(FileData);
 end;
 
 // Lee 1000 Registros en una Sola Operación de Acceso a Disco y los Muestra en un ListBox
 procedure TForm1.Button3Click(Sender: TObject);
 var
    i : Integer;
 begin
    FillChar(ArrayData,SizeOf(ArrayData),0);
    AssignFile(FileData, FileName);
    Reset(FileData);
    Seek(FileData, 0);
    BlockRead(FileData, ArrayData, CountReg);
    for i := 0 to CountReg - 1 do
    begin
       ListBox1.Items.Add(ArrayData[i].Name
                          + ' '
                          + IntToStr(ArrayData[i].PIN)
                          + ' '
                          + DateTimeToStr(ArrayData[i].DateData));
    end;
    CloseFile(FileData);
 end;
 
 // Clear el ListBox de Registros
 procedure TForm1.Button4Click(Sender: TObject);
 begin
    ListBox1.Clear;
 end;
 
 end.
El código anterior en Delphi 7 bajo Windows 7 Professional x32, permite leer y grabar bloques de registros de un archivo en una sola operación de acceso a disco.

Nota: Excelente técnica ecfisa ^\||/

Espero sea útil :)

Nelson.

ecfisa 04-09-2014 16:18:45

Hola nlsgarcia.

Es un resabio del viejo Turbo Pascal... :), con Delphi ya podemos hacer:
Código Delphi [-]
...
const
  MAXDATA = 100;

type
  TReg = packed record
    dato: string[20];
    posi: integer;
  end;
  TFileReg = file of TReg;

var
  fr: TFileReg;
  rg: TReg;
  vr: array[0..MAXDATA] of TReg;
  FName: string;

// inicializar
procedure TForm1.FormCreate(Sender: TObject);
begin
  FName:= ExtractFilePath(Application.ExeName) + 'prueba.dat';
  AssignFile(fr, FName);
  try
    Reset(fr);
  except
    Rewrite(fr);
  end;
  CloseFile(fr);
  Randomize;
end;

// guardar
procedure TForm1.btnWriteClick(Sender: TObject);
var
  i: Integer;
begin
  // algunos datos...
  for i:= 0 to MAXDATA-1 do
  begin
    vr[i].dato:= Format('Registro %d',[i+1]);
    vr[i].posi:= i;
  end;

  // guardar 
  with TFileStream.Create(FName, fmOpenWrite) do
  try
    Position:= 0;
    Write(vr, MAXDATA * SizeOf(rg));
  finally
    Free;
  end;
end;

// leer
procedure TForm1.btnReadClick(Sender: TObject);
begin
  with TFileStream.Create(FName, fmOpenRead) do
  try
    Position:= 0;
    Read(vr, MAXDATA * SizeOf(rg));
  finally
    Free;
  end;
end;

// mostrar
procedure TForm1.btnShowClick(Sender: TObject);
var
  i: Integer;
begin
  with ListBox1.Items do
  begin
    Clear;
    for i:= 0 to MAXDATA-1 do
      Add(Format('%s %d',[vr[i].dato, vr[i].posi]));
  end;
end;
con el mismo resultado.

Saludos :)

tarco35 05-09-2014 21:09:11

Muchas gracias.... con esto y creando un fichero indice que me indique en que posición esta para poder hacer un acceso directamente a la posición de lo que quiero leer o modificar.
Pero si quiero añadir, como tendría que hacerlo?... un seek al final de fichero??? o como.

Gracias por su ayuda.

ecfisa 05-09-2014 21:23:11

Hola tarco35.
Cita:

Empezado por tarco35 (Mensaje 480770)
...
Pero si quiero añadir, como tendría que hacerlo?... un seek al final de fichero??? o como.

Exáctamente, posicionándote al final del archivo.

Agregar un registro:
Código Delphi [-]
  Seek(FileReg, FileSize(FileReg));
  Write(FileReg, Reg);

Leer último registro:
Código Delphi [-]
  Seek(FileReg, FileSize(FileReg)-1);
  Read(FileReg, Reg);

Mostrar posición del registro actual:
Código Delphi [-]
  ShowMessage(Format('Posición actual en el archivo: %d', [FilePos(FileReg)]));

Saludos :)

tarco35 06-09-2014 20:24:26

gracias....

nlsgarcia 07-09-2014 16:53:28

tarco35,

Cita:

Empezado por ecfisa
...Es un resabio del viejo Turbo Pascal... :), con Delphi ya podemos hacer...con el mismo resultado...

^\||/

Revisa este código:
Código Delphi [-]
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    ListBox1: TListBox;
    Button4: TButton;
    Button5: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Button4Click(Sender: TObject);
    procedure Button5Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TData = record
     Name : Array[0..29] of Char;
     PIN : Integer;
     DateData : TDateTime;
  end;

const
  CountReg = 1000;

var
  Form1: TForm1;
  ArrayData : Array[0..CountReg-1] of TData;
  RegData : TData;
  FileName : String;
  F : TFileStream;

implementation

{$R *.dfm}

// Inicializa la Aplicación
procedure TForm1.FormCreate(Sender: TObject);
begin
   Randomize;
   FileName := ExtractFilePath(Application.ExeName) + 'Data.txt';
end;

// Genera un Arreglo de Registros de 1000 Elementos
procedure TForm1.Button1Click(Sender: TObject);
var
   i : Integer;

begin

   FillChar(ArrayData,SizeOf(ArrayData),0);

   for i := 0 to CountReg - 1 do
   begin
      StrPCopy(ArrayData[i].Name,'Name-' + IntToStr(i));
      ArrayData[i].PIN := Random(1000);
      ArrayData[i].DateData := Now + Random(365);
   end;

end;

// Graba 1000 Registros en una Sola Operación de Acceso a Disco
procedure TForm1.Button2Click(Sender: TObject);
begin

   F := TFileStream.Create(FileName, fmCreate, fmShareExclusive);
   F.Write(ArrayData, SizeOf(ArrayData));
   F.Free;

end;

// Lee 1000 Registros en una Sola Operación de Acceso a Disco y los Muestra en un ListBox
procedure TForm1.Button3Click(Sender: TObject);
var
   i : Integer;

begin

   FillChar(ArrayData,SizeOf(ArrayData),0);

   F := TFileStream.Create(FileName, fmOpenRead, fmShareDenyNone);
   F.Read(ArrayData, SizeOf(ArrayData));
   F.Free;

   for i := 0 to CountReg - 1 do
   begin
      ListBox1.Items.Add(ArrayData[i].Name
                         + ' '
                         + IntToStr(ArrayData[i].PIN)
                         + ' '
                         + DateTimeToStr(ArrayData[i].DateData));
   end;

end;

// Clear el ListBox de Registros
procedure TForm1.Button4Click(Sender: TObject);
begin
   ListBox1.Clear;
end;

// Muestra la data de un registro n 
procedure TForm1.Button5Click(Sender: TObject);
var
   NumReg : String;
   DataReg : string;
   PosReg : Integer;
   MsgApp : String;

begin

   NumReg := InputBox('Número de Registro a Consultar', 'NumReg', '1');

   F := TFileStream.Create(FileName, fmOpenRead, fmShareDenyNone);
   
   if StrToIntDef(NumReg,1) > F.Size div SizeOf(RegData) then
   begin
      MsgApp := Format('Número de Reg Invalido, El Archivo tiene %d Reg',[F.Size div SizeOf(RegData)]);
      MessageDlg(MsgAPP,mtInformation,[mbOK],0);
      F.Free;
      Exit;
   end;

   PosReg := (StrToIntDef(NumReg,1) - 1) * SizeOf(RegData);

   F.Seek(PosReg, soFromBeginning);
   F.Read(RegData, SizeOf(RegData));
   DataReg := RegData.Name
              + ' '
              + IntToStr(RegData.PIN)
              + ' '
              + DateTimeToStr(RegData.DateData);

   ShowMessage(DataReg);

   F.Free;

end;

end.
El código anterior en Delphi 7 bajo Windows 7 Professional x32, permite leer y grabar bloques de registros de un archivo en una sola operación de acceso a disco con TFileStream y consultar registros individuales de forma aleatoria.

Espero sea útil :)

Nelson.


La franja horaria es GMT +2. Ahora son las 17:24:03.

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