24. oktober 2002 - 17:19Der 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.
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);
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! ;)
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.
>>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? :)
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
Synes godt om
Ny brugerNybegynder
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.