Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Problem beim Datei auslesen in ein Array (https://www.delphipraxis.net/77592-problem-beim-datei-auslesen-ein-array.html)

Quick_silver 21. Sep 2006 16:47


Problem beim Datei auslesen in ein Array
 
Ich will eine Datei auslesen.
Dafür habe folgenden Code:

Inhalt der Datei:
02 00 00 00 01 00 <ID 21 A1 07 00> <Stringlänge 00 13> 00 <string>
<ID> <Stringlänge> 00 <string>
<ID> <Stringlänge> 00 <string>
etc...

Delphi-Quellcode:
    fs.Seek(6,0); //Die ersten Bytes überspringen

    fs.Read(id, 4);
    fs.Seek(1, 1); //Ein byte überspringen (gibt es ne bessere lösung?)
    fs.Read(Len, 2);

    SetLength(text, Len);
    fs.Read(PChar(text)^, Len);

    //daten[i].id := id;
    //daten[i].text := text;
DIe Daten will ich in dieses Array:
Delphi-Quellcode:
type
  TDatensatz = record
    ID: integer;
    Text: AnsiString;
  end;

  TDatenArray = array of TDatensatz;
Und das ist mein versuch der imemr irgnedwleche Speicherzugriffsfehler auswirft und das Programm crasht:

Delphi-Quellcode:
procedure TForm1.ReadData(datei : string; var daten : TDatenArray );
var
fs : TStream;
i, id, Len : Integer;
text : string;
begin
  fs := TFileStream.Create(datei, fmOpenReadWrite);

  fs.Seek(6,0);
  i := 0;

  while fs.Position < fs.Size do
  begin
    inc(i);
    SetLength( daten, i );

    fs.Read(id, 4);
    fs.Seek(1, 1); //Will ich weg haben
    fs.Read(Len, 2); //Wieso nur 2 bytes?

    SetLength(text, Len);
    fs.Read(PChar(text)^, Len);

    daten[i].id := id;
    daten[i].text := text;

    //Immerhin funktionniert die schleife überhaupt erst mit der folgenden Zeile. *schulterzuck*
    //Ohne diel iest er nur den ersten eintrag.
    ListBox.Items.Add( IntToStr(fs.Position) +'<'+IntToStr(fs.Size) );
  end;
  fs.Free;
end;
Wie kann ich das ganze eleganter lösen?

panzerfischer 21. Sep 2006 16:52

Re: Problem beim Datei auslesen in ein Array
 
was soll denn in der datei stehen (bitte nicht in einsen und nullen(auch kein hexcode)) man muss es ja nicht schlimmer machen als es ist

Quick_silver 21. Sep 2006 16:57

Re: Problem beim Datei auslesen in ein Array
 
Eine ID (Integer) und ein String der zu dieser ID gehört.
Davon einige tausend.
Könnte man aus dem gepostet Code auch erahnen :/

Das auslesen funktioniert ja auch grob so. Also die Variablen ID und Text werden schon richtig gefüllt.

panzerfischer 21. Sep 2006 17:03

Re: Problem beim Datei auslesen in ein Array
 
also die typdeklaration ist schon mal gut, ansonsten, warum ließt du nicht die datei im ganzen aus?

z.b. so:
Delphi-Quellcode:
type TDatensatz = record ID: integer; Text: AnsiString; end;

var TDatenArray = array[0..viel] of TDatensatz;
     TDatenfile = file of datensatz;

..

assignfile(TDatenfile,'pfad/datei');
{$I-} //eingabe/ausgabe fehler werden ignoriert
reset(TDatenfile);
{$I+}
if IoResult = 0 then begin
  i:=0;
  while not eof do {end of file}
    read(TDatenfile,TDatenarray[i]);
  inc(i);
end;
closefile(TDatenfile);
speichern funktioniert ähnlich. hat halt den nachteil, dass du die größe vom array festlegen musst, weil du vorher nicht weißt wieviel drinne steht
außerdem musst du die länge des strings festlegen, weil der rechner ja sonst nicht weiß, wie lang die datei nun ist

Quick_silver 21. Sep 2006 17:09

Re: Problem beim Datei auslesen in ein Array
 
Also
var TDatenArray = array[0..viel] of TDatensatz;
kann ich schlecht nehmen, ich muss schon vorher rausfinden wie viele DAtensätze ich habe, oder das array dynamisch während des auslesens erweitern.

Zudem wird dein Vorschlag wohl 6 bytes zu fürh anfangen zu lesen, oder nicht?

Die Länge der Text Variable muss ebenfalls vor jedem Eintrag neu fest gelegt werden. Da die Strings ja nicht immer gleich lang sein. Eigentlich so gut wie nie.

panzerfischer 21. Sep 2006 17:30

Re: Problem beim Datei auslesen in ein Array
 
eigendlich nicht, da die 6byte zum kopf gehören, und nicht ausgelesen werden, bei der größe der strings musst du wissen, mit welcher größe die gespeichert wurden, damit es nicht zu verschiebungen kommt, kann aber auch sein, das der computer erkennt, wie groß der string ist, da nomalerweise vor dem ersten buchstaben die länge steht, musst du mal ausprobieren

ein dynamisches array erweitern könnte gut funktionieren

woher kommt die datei, bzw. womit hast du sie erstellt?

SirThornberry 21. Sep 2006 17:35

Re: Problem beim Datei auslesen in ein Array
 
Zitat:

Zitat von panzerfischer
also die typdeklaration ist schon mal gut, ansonsten, warum ließt du nicht die datei im ganzen aus?

z.b. so:
Delphi-Quellcode:
type TDatensatz = record ID: integer; Text: AnsiString; end;

var TDatenArray = array[0..viel] of TDatensatz;
     TDatenfile = file of datensatz;

..

assignfile(TDatenfile,'pfad/datei');
{$I-} //eingabe/ausgabe fehler werden ignoriert
reset(TDatenfile);
{$I+}
if IoResult = 0 then begin
  i:=0;
  while not eof do {end of file}
    read(TDatenfile,TDatenarray[i]);
  inc(i);
end;
closefile(TDatenfile);
speichern funktioniert ähnlich. hat halt den nachteil, dass du die größe vom array festlegen musst, weil du vorher nicht weißt wieviel drinne steht
außerdem musst du die länge des strings festlegen, weil der rechner ja sonst nicht weiß, wie lang die datei nun ist

Das geht nicht weil in TDatensatz ein Ansistring enthalten ist was widerum nur ein Pointer ist.

@Quick_silver: Wenn Len bei dir ein Integer (4 Byte) ist und du mit
Delphi-Quellcode:
fs.Read(Len, 2);
nur 2 Byte in diese Variable einliest sind die anderen 2 Byte weiterhin undefiniert. Das heißt in den restlichen 2 Byte steht weiter irgendwelcher Zufallsmüll. Entweder nimmst du als Typ "word" oder initialisierst die Variable vorher mit "0".
Am besten du debugst das ganze mal und prüfst nach jedem schritt welche Werte die Variablen haben. Dann weißt du auch wo du daneben greifst.

Der_Unwissende 21. Sep 2006 17:39

Re: Problem beim Datei auslesen in ein Array
 
Hi,
kannst du dann vielleicht eine solche Datei posten?

Ansonsten sehe ich nicht ganz warum dein Code nur so arbeiten sollte.
Delphi-Quellcode:
var List : TList;
    fs : TFileStream;
    buffer : ^TDatensatz;
    length : Integer;
begin
  list := Tlist.Create;
  ...

  try
    while (fs.Position < fs.Size) do
    begin
      new(buffer);
     
      fs.Read(buffer.id, 4);
      fs.Position := fs.Position + 1;
      fs.Read(length, 2);
      fs.Position := fs.Position + 1;
   
      setLength(buffer.Text, length);
     
      fs.Read(buffer.Text, length);

      list.Add(buffer);
    end;
  finally
    fs.Free;
  end;
end;
So sollte das ganze eigentlich klappen (wenn die Datei so aufgebaut ist wie du sagst (und natürlich ich keinen Fehler gemacht habe). An sich empfiehlt sich hier eine Liste. Intern wird zwar auch ein Array verwendet und du kannst auch per Index wahlfrei auf bestimmte Elemente zugreifen, aber die Größenanpassung ist hier von Delphi übernommen. Dein Array immer nur um 1 Element zu erweitern ist sehr schlecht. Es kostet Zeit neuen Speicher zu allozieren und das alte Array dort reinzukopieren. Eine List alloziert gleich eine vielzahl von weiteren Elementen. Sind diese neu allozierten Plätze zu einem gewissen Grad gefüllt, wird wieder um ein gutes Stück vergrößert. Hast du einen Overhead (an Zeit) von O, dann teilt der sich damti auf die Anzahl n der allozierten Elemente auf, ist also in deinem Fall 0/1 = O und das in jeder Iteration, im Falle der Liste O/n und n ist halt von Delphi gewählt (und das passiert automatisch).

Gruß Der Unwissende

[edit]
Delphi Tag geöffnet, quote geschlossen...
[/edit]

panzerfischer 21. Sep 2006 17:42

Re: Problem beim Datei auslesen in ein Array
 
ansistring sagt doch nur aus, das max. 2^31buchstaben gespeichert werden können. vor jedem string steht die länge des strings also die ersten 4byte in diesem fall, die auskunft über die länge geben.

könnte sogar so sein, das es sich bei dmn integer wert in seiner datei, um die länge des strings handelt, ich weiß ja nicht genau, was das für ne file ist

SirThornberry 21. Sep 2006 17:45

Re: Problem beim Datei auslesen in ein Array
 
Zitat:

Zitat von panzerfischer
ansistring sagt doch nur aus, das max. 2^31buchstaben gespeichert werden können. vor jedem string steht die länge des strings also die ersten 4byte in diesem fall, die auskunft über die länge geben.

könnte sogar so sein, das es sich bei dmn integer wert in seiner datei, um die länge des strings handelt, ich weiß ja nicht genau, was das für ne file ist

Ansistring sagt aus das es String mit variabler Länge ist und somit nur ein Pointer. Bei einem Ansistring liegen die eigentlichen Daten also irgendwo und nicht hinter der Adresse der Variablen.
Du kannst ja mal SizeOf(DeineAnsiStringVariable) ausgeben lassen. Du wirst immer 4 zurück bekommen weil der AnsiString eben nur 4 Byte groß ist (bei einem 32bit compiler)


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:32 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz