Avatar billede runem74 Nybegynder
24. oktober 2002 - 17:19 Der er 8 kommentarer og
2 løsninger

Loade file of record...

Hej,

Jeg har lavt en file of record v.hj.a. følgende kode:

procedure TForm1.Button1Click(Sender: TObject);
var
X:File of massrecordtype;
I:real;
J,antal:integer;
begin
antal:=listbox1.items.count;
setlength(massarray,antal);
Assignfile(X,'c:\a.dat');
rewrite(X);
for J:=0 to antal-1 do
  begin
  massarray[J].mass:=strtofloat(listbox1.items[J]);
  massarray[J].typ:=1;
  write(X,massarray[J]);
  end;
Closefile(X);
end;

Jeg ønsker nu at loade den ind igen på et senere tidspunkt men så skal jeg jo vide hvor stor den er for at kunne bruge setlength(massarray). Kan man ikke dynamisk oprette nye records.

Mange hilsner,

Rune
Avatar billede borrisholt Novice
24. oktober 2002 - 17:22 #1
brug TWriter og TReader i stedet !

Jens B
Avatar billede borrisholt Novice
24. oktober 2002 - 21:17 #2
prøv en form med to knapper, og et Memo felt også det her kode :

unit Unit1;

interface

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

type

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Memo1: TMemo;
    procedure Button2Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
  private
  public
    { Public declarations }
  end;

  THesteRecord = record
    EnStreng  : String;
    EnInteger : Integer;
    EnInt64  : Int64;
    EnFloat  : Currency;
    //Find Selv på flere;
  end;

  THorseWriter = class (TWriter)
  public
    Procedure WriteHesteRecord(const HesteRecord : THesteRecord);
  end;

  THorseReader = class (Treader)
  public
    Procedure ReadHesteRecord(var HesteRecord : THesteRecord);
  end;
var
  Form1: TForm1;

implementation

{$R *.DFM}

{ THorseWriter }

procedure THorseWriter.WriteHesteRecord(const HesteRecord: THesteRecord);
begin
  with HesteRecord do
  begin
    WriteString(EnStreng);
    WriteInteger(EnInteger);
    WriteInteger(EnInt64);
    WriteCurrency(EnFloat);
  end;
end;

{ THorseReader }

procedure THorseReader.ReadHesteRecord(var HesteRecord: THesteRecord);
begin
  with HesteRecord do
  begin
    EnStreng  := ReadString;
    EnInteger := ReadInteger;
    EnInt64  := ReadInt64;
    EnFloat  := ReadCurrency;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  HorseWriter : THorseWriter;
  Stream      : TFileStream;
  i : Integer;
  HesteRecord : THesteRecord;
begin
  Stream      := TFileStream.Create('Her er en fil fyldt med heste.hest', fmCreate or fmOpenReadWrite);
  HorseWriter := THorseWriter.Create(Stream, $ff);
  HorseWriter.WriteListBegin;
  for i := 2 to 6 do
  begin
    with HesteRecord do
    begin
      EnStreng := 'Ude på marken står der '+IntToStr(i)+' Heste';
      EnInteger := i;
      EnInt64  := i;
      EnFloat  := i / 7;
    end;
    HorseWriter.WriteHesteRecord(HesteRecord);
  end;
  HorseWriter.WriteListEnd;
  FreeAndNil(HorseWriter);
  FreeAndNil(Stream);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  HorseReader : THorseReader;
  Stream      : TFileStream;
  i : Integer;
  HesteRecord : THesteRecord;
begin
  Memo1.Clear;
  Stream      := TFileStream.Create('Her er en fil fyldt med heste.hest', fmOpenRead);
  HorseReader := THorseReader.Create(Stream, $FF);
  HorseReader.ReadListBegin;
  for i := 2 to 6 do
  begin
    HorseReader.ReadHesteRecord(HesteRecord);
    Memo1.Lines.Add('====');
    with HesteRecord do
    begin
      Memo1.Lines.Add(EnStreng);
      Memo1.Lines.Add(IntToStr(EnInteger));
      Memo1.Lines.Add(IntToStr(EnInt64));
      Memo1.Lines.Add(FloatToStr(EnFloat));
    end;
  end;
  HorseReader.ReadListEnd;
  FreeAndNil(HorseReader);
  FreeAndNil(Stream);

end;

end.


Jens B
Avatar billede borrisholt Novice
24. oktober 2002 - 21:17 #3
Mængden af heste er vigtig !

Jens B
Avatar billede hermandsen Juniormester
25. oktober 2002 - 02:48 #4
Var det ikke en ide først at skrive i filen hvor mange records den indeholder!?

I stedet for at bruge file of record skal du så bare bruge file:

type
  THest = record
    Mule: Real;
    Hale: Integer;
  end;

var
  F: File;
  Antal, I: Integer;
  HesteArray: array of THest;
begin
  AssignFile(F, 'c:\a.dat');
  Rewrite(F, 1);
  Antal := ListBox1.Items.Count;
  BlockWrite(F, Antal, SizeOf(Integer));
  SetLength(HesteArray, Antal);
  for I := Low(HesteArray) to High(HesteArray) do
  begin
    HesteArray[I].Mule := StrToFloat(ListBox1.Items[I]);
    HesteArray[I].Hale := 1;
    BlockWrite(F, HesteArray[I], SizeOf(THest));
  end;
  CloseFile(F);
end;

Du behøver sådan set ikke array'et i dette eksempel, men efter som du så ud til at være så glad for det, så lod jeg det bare blive! ;)

Hvis du så skal loade det hele ind i array'et igen, så kan du bruge det her:

type
  THest = record
    Mule: Real;
    Hale: Integer;
  end;

var
  F: File;
  Antal, I: Integer;
  HesteArray: array of THest;
begin
  FileMode := fmOpenRead;
  AssignFile(F, 'c:\a.dat');
  Reset(F, 1);
  BlockRead(F, Antal, SizeOf(Integer));
  SetLength(HesteArray, Antal);
  for I := Low(HesteArray) to High(HesteArray) do
  begin
    BlockRead(F, HesteArray[I], SizeOf(THest));
    ListBox1.Items[I].Caption := FloatToStr(HesteArray[I].Mule);
//    HesteArray[I].Hale := 1; Jeg ved ikke lige hvad du vil med den, men det er jo op til dig
  end;
  CloseFile(F);
end;

Det var sådan hvad jeg lige kunne ryste ud af ærmet... Jeg er ikke sikker på at borrisholt mener jeg har brugt nok heste i mit eksempel, men det virker sådan set fint for mig! ;)

//hermandsen
Avatar billede runem74 Nybegynder
25. oktober 2002 - 08:27 #5
Ja, jeg overvejede også at skrive længden i starten af filen. Det jeg så ville have gjort var at skrive længden i den første record. Det er dog ikke altid at mine records indeholder integer så det var ikke en god løsning. Ovenstående er dog fint til mit behov.

Mange tak,

Rune
Avatar billede borrisholt Novice
25. oktober 2002 - 08:41 #6
Fordelen ved "min" metode er at man kan læse og skrive strings.

Jens B
Avatar billede hermandsen Juniormester
25. oktober 2002 - 09:21 #7
>>borrisholt
Hvordan gemmer den egentlig de strings? Afsluttet med #0-karakter, eller skriver den først længden af strengen før selve strengen?

>>runem74
Denne her metode virker hvis du vil skrive strings ned i en file-variabel:
http://www.eksperten.dk/spm/177987 ;)
Avatar billede borrisholt Novice
25. oktober 2002 - 09:35 #8
hermandsen >>

Kig på mit eksempel med TWriter og TReader ovenfor der gemmer jeg en String !

JEns B
Avatar billede hermandsen Juniormester
25. oktober 2002 - 11:25 #9
>>Jens B
Ja, men hvordan gemmes det i filen? Du kalder jo bare WriteString som er en procedure i TWriter-klassen...

Jeg kiggede lige på den og det ser således ud i kildekoden:

procedure TWriter.WriteString(const Value: string);
var
  L: Integer;
begin
  L := Length(Value);
  if L <= 255 then
  begin
    WriteValue(vaString);
    Write(L, SizeOf(Byte));
  end else
  begin
    WriteValue(vaLString);
    Write(L, SizeOf(Integer));
  end;
  Write(Pointer(Value)^, L);
end;

Proceduren Write som kaldes så mange gange (WriteValue benytter også Write) er så en assembler procedure, hvilket jeg desværre ikke ved så meget om...

Helt ærligt, så tror jeg ikke der er den store forskel mellem TWriter/TReader og Delphi's egen file-variabel hvad angår hastighed...
Hvad tror du Jens? Flere heste? :)
Avatar billede borrisholt Novice
25. oktober 2002 - 11:35 #10
Jeg har som aldrig lavet nogle performance tests af det .. Men mon ikkee det er det samme ?

Men ud over det så skal der altid flere heste til :-)

Jens B
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester