Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Datei mit FileStream auslesen (https://www.delphipraxis.net/154085-datei-mit-filestream-auslesen.html)

delphinewbie 27. Aug 2010 07:36

Delphi-Version: 2005

Datei mit FileStream auslesen
 
Guten Morgen Delphi-Gemeinde,
ich habe mich hier gerade angemeldet und das nicht ohne Grund. Ich bin gerade dabei, mich ein wenig ins Delphi einzuarbeiten und auf der Suche nach geballtem Wissen bin ich nun hier gelandet. Ich habe den Eindruck, dass mir hier geholfen werden kann. Also wie gesagt, ich bin ein absoluter Einsteiger und ich hoffe, dass ihr mir meine vllt. primitiven Fehler verzeiht. Doch nun zu meinem Problem :
Ich möchte eine typisierte (oder heißt das strukturierte ) Datei (Byte für Byte) auslesen und die darin enthaltenen Daten natürlich weiterbearbeiten. Mir ist auch bekannt, wie diese Datei aufgebaut ist, d.h. wo steht ein String, wie lang ist er, wo steht ein integer u.s.w. und ich erhalte auch sinnvolle Daten, wie sie zu erwarten wären. Leider erhalte ich dann jedoch beim Beenden des Programms (in der IDE) eine Fehlermeldung.

Im Projekt xxx.exe ist eine Exception der Klasse EAccessViolation aufgetreten. Meldung : 'Zugriffsverletzung bei Adresse 0040438A in Modul 'xxx.exe'. Lesen von Adresse 00000018'.
Prozess wurde angehalten. Mit einzelne Anweisung oder Start fortsetzen.

Starte ich die xxx.exe bspw. aus dem Windows-Explorer, kommt nach Programmbeendigung die Meldung :
xxx.exe funktioniert nicht mehr
Windows kann online nach einer Lösung für das Problem suchen.
u.s.w blabla....


Quellcode (Ausschnitt) :

type

bytes = record

// Global section
FileID : word;
data_offset : Longint;
L_of_Filecomment : word;
Filecomment : string;
Length_of_Reserve_string : array[1..32] of byte;
Reserve_string : array[1..32] of string;
end;

var
Form1: TForm1;
f : TFileStream;
ds: bytes;

implementation
.
.
.

if OpenDialog1.Execute then
begin
f:=(TFileStream.Create(OpenDialog1.FileName,fmOpen Read));
pfad:= OpenDialog1.FileName;

with f do begin
Read(ds.FileID,sizeof(word));
Read(ds.data_offset,sizeof(longint));
Read(ds.L_of_Filecomment,sizeof(word));
if ds.L_of_Filecomment <> 0 then
Read(ds.Filecomment[1],ds.L_of_Filecomment);
for i:=1 to 32 do begin
Read(ds.Length_of_Reserve_string[i],sizeof(word));
Read(ds.Reserve_string[i],ds.Length_of_Reserve_string[i]);
end;

Read(ds.NofChan,sizeof(word));
Read(ds.max_chan_length,sizeof(longint));
.
.
.
.
end; // end with f do
f.Free;
end; // if OpenDialog1.Execute
.
.

Das Eigenartige an der Sache ist jedoch, dass diese Fehler nicht auftreten, wenn alles ab der for-Schleife auskommentiert wird. Beginnt die Auskommentierung nur 3 Zeilen weiter, also bei Read(ds.NofChan,sizeof(word));, habe ich schon die Fehlermeldung!!! Hängt es irgendwie mit der for-Schleife zusammen oder mache ich bei den String-Arrays Fehler ?
Hat jemand eine Idee zu diesem sicherlich einfachen Problem ?
Vielen Dank,
delphinewbie

DeddyH 27. Aug 2010 09:37

AW: Datei mit FileStream auslesen
 
Hallo und Willkommen in der DP :dp:,

ich denke, das Hauptproblem sind die Strings. Ein String ist in Delphi(2 - 2007) ein AnsiString, in neueren Versionen ein Unicode-String. AnsiStrings sind intern nur erst einmal ein Zeiger, also 4 Byte groß. Speicherst Du diesen und lädst ihn wieder, ist dieser Zeiger ungültig bzw. zeigt ganz woanders hin. Um das zu umgehen, solltest Du ShortStrings verwenden, diese sind allerdings auf 256 Zeichen begrenzt. Brauchst Du mehr, musst Du wohl auf statische Char-Arrays ausweichen.

Gausi 27. Aug 2010 10:07

AW: Datei mit FileStream auslesen
 
Das Problem dürfte sein, dass du die Länge der Strings vorher nicht pasend setzt. So sollte das gehen:
Delphi-Quellcode:
for i:=1 to 32 do
begin
  Read(ds.Length_of_Reserve_string[i],sizeof(word));
  SetLength(ds.Reserve_string[i], ds.Length_of_Reserve_string[i])
  Read(ds.Reserve_string[i][1], ds.Length_of_Reserve_string[i]);
end;
Also: Erst die Länge des Strings aus der Datei lesen, diese Länge auf den String übertragen, und dann die Daten in den String laden, Startposition ist dann das erste Zeichen in dem String.

delphinewbie 27. Aug 2010 10:14

AW: Datei mit FileStream auslesen
 
Hi DeddyH,
ne, hat nicht geholfen. Der Zeiger wird doch aber nicht verändert, wenn ich die Datei nur hintereinander auslese, oder ? Und wie gesagt, die Datei wird ja auch richtig ausgelesen.
Die Fehlermeldung kommt erst beim Beenden des Programms , also der xxx.exe.
Es sieht ja fast so aus, als ob dann beim Programmbeenden eine unzulässige Adresse angesprochen wird. Aber wieso ?
Gibt es eigentlich noch andere Möglichkeiten außer mit TFileStream, derartige Dateien auszulesen ? Den Dateien kann man auch keine konstante Struktur zuordnen, sodass man mit records hätte arbeiten können.
Das Problem dabei ist ja, dass die Dateilänge nie gleich ist, abhängig davon z.B. wie lang Kommentare sind oder wieviele Datenkanäle abgespeichert wurden. Diese Angaben finde ich immer erst direkt in der Datei, aber das funktioniert ja auch richtig. Nur eben das Ende...

Vielen Dank

delphinewbie 27. Aug 2010 10:20

AW: Datei mit FileStream auslesen
 
@Gausi,
danke, aber ich bekomme die gleiche Fehlermeldung, nur sind die Adressen, bei denen die Zugriffsverletzung auftritt anders.

Ich bin ratlos :cry:

DeddyH 27. Aug 2010 10:25

AW: Datei mit FileStream auslesen
 
Zitat:

Delphi-Quellcode:
Length_of_Reserve_string : array[1..32] of byte;
...
Read(ds.Length_of_Reserve_string[i],sizeof(word));

Das Array ist 32 Byte groß, Du liest aber 64 Byte (Word = 16 Bit). Außerdem müsstest Du (wenn ich das richtig sehe) wohl erst das Byte-Array komplett befüllen und erst anschließend das String-Array.

delphinewbie 27. Aug 2010 10:54

AW: Datei mit FileStream auslesen
 
ok, habe das array jetzt auf word gesetzt.

Length_of_Reserve_string : array[1..32] of word;
Reserve_string : array[1..32] of string;

Ich kann aber nicht erst das eine array füllen und dann das andere, weil die Reichenfolge beim Lesen eben so ist :
1. Lesen von 2 bytes (Länge L des nachfolgenden strings
2. Lesen von L*bytes ( der string selbst)
Oder habe ich dich falsch verstanden ?

Fehlermeldung bleibt leider immer die gleiche

DeddyH 27. Aug 2010 11:00

AW: Datei mit FileStream auslesen
 
Ob die Reihenfolge und die Datentypen so stimmen, weiß ich nicht, das hängt ja vom Dateiformat ab und nicht davon, wie Du den Record definierst.

delphinewbie 27. Aug 2010 11:22

AW: Datei mit FileStream auslesen
 
genau, und wenn die Daten aber richtig eingelesen werden (Vergleichbarkeit ist vorhanden), muss ja wohl von der Seite her alles o.k. sein.
Trotzdem muss ich irgendwas vergessen haben.Vllt. muss Speicher freigegeben werden oder die Datei wird nicht korrekt 'geschlossen' ?

Ich werde mal noch ein bissl probieren...

p80286 27. Aug 2010 11:26

AW: Datei mit FileStream auslesen
 
Hallo Delphinewbie,

zunächst solltest Du Dich mit dem Debugger (Tasten:F7, F8, F4 F5) vertraut machen, da kann man meist sehen wohin was gelesen wird.

Dann verwendest Du z.B.

Delphi-Quellcode:
Length_of_Reserve_string : array[1..32] of word;
1. Du bist sicher das es nur max. 32 Strings gibt?
2. Da ich die Struktur in Deiner Datei nicht kenne, ein Vorschlag ins Blaue

Delphi-Quellcode:
Type
  mytype=record
           Feld1 : word;
           Feld2 : integer;
           ....
           textfeld : ansistring;
        end;
Den Weg den Du gewählt hast, halte ich für gefährlich, da zwei Werte die Länge eines Strings und der String selber in unterschiedlichen Variablen aufgenommen werden. Beide Werte gehören zusammen, und sollten nicht willkürlich getrennt werden.

Gruß
K-H

P.S.
Zitat:

Vllt. muss Speicher freigegeben werden oder die Datei wird nicht korrekt 'geschlossen' ?
Dann sollte der Debugger erst recht bemüht werden!

blackfin 27. Aug 2010 11:39

AW: Datei mit FileStream auslesen
 
Auch wenn es mit dem Fehler nichts direkt zu tun hat:
Zusätzlich zu den genannten Dingen solltest du dir vielleicht überlegen, deinen Record-Typ nicht bytes zu nennen.

Ich weiss, standardmäßig ist bytes nicht definiert, aber der Name wäre mir zu generisch und würde mir Bauchschmerzen in Hinblick auf die Zukunft bereiten. Eventuell kommt es irgendwann deswegen zu sehr merkwürdigen Fehlern, die man nicht mehr wirklich versteht, ähnlich wie wenn man reserved words von SQL-Datenbanken als Feldnamen benutzt oder Vergleichbares.
Zudem kommt, dass der Name so wenig aussagekräftig ist, dass du vielleicht in einem halben Jahr nicht mehr weisst, warum das Ding "bytes" heisst, obwohl es ja die Struktur einer definierten Datei angibt und nicht nur "irgendwelche Bytes". Nenn das Ding lieber nach dem Typ der Datei, je nachdem was es ist. Also zum Beispiel: CustomerFileBytes TCustomerFileBytes oder was weiss ich sonst :)

himitsu 27. Aug 2010 11:54

AW: Datei mit FileStream auslesen
 
Zitat:

Zitat von blackfin (Beitrag 1045498)
Ich weiss, standardmäßig ist bytes nicht definiert, aber der Name wäre mir zu generisch und würde mir Bauchschmerzen in Hinblick auf die Zukunft bereiten.

Da wir unsere Typen meißt mit einem T kennzeichnen ... TBytes gibt es schon.

blackfin 27. Aug 2010 12:01

AW: Datei mit FileStream auslesen
 
Rüschtüsch...also gleich mal den Vorschlag korrigieren :)

DeddyH 27. Aug 2010 12:05

AW: Datei mit FileStream auslesen
 
Delphi-Quellcode:
type
  TEinEindeutigerNameOhneVerwechslungsgefahr = record
:mrgreen:

delphinewbie 30. Aug 2010 08:16

AW: Datei mit FileStream auslesen
 
Hi,
danke für eure Tipps. Habe es umbenannt, nur ist das leider nicht mein Problem...
Ich möchte nochmal nachhaken : Ist TFilestream tatsächlich die einzige Variante, derartige Dateien auszulesen ?

tschüß

DeddyH 30. Aug 2010 08:19

AW: Datei mit FileStream auslesen
 
Nö, TMemoryStream z.B. ginge auch. Was wohl nicht (so einfach) geht, ist das althergebrachte satzweise Lesen, da die Größe des Blocks ja variiert.

himitsu 30. Aug 2010 08:31

AW: Datei mit FileStream auslesen
 
Wie sieht denn dein Code nun aktuell aus?

PS:
Code:
Read(ds.Length_of_Reserve_string[i],sizeof(word));
Hier ließt man ein WORD, aber die Variable ist nur ein BYTE groß.

DeddyH 30. Aug 2010 08:32

AW: Datei mit FileStream auslesen
 
Zitat:

Zitat von himitsu (Beitrag 1046022)
Code:
Read(ds.Length_of_Reserve_string[i],sizeof(word));
Hier ließt man ein WORD, aber die Variable ist nur ein BYTE groß.

*Seufz* das hatte ich in #6 bereits erwähnt :roll:

delphinewbie 30. Aug 2010 08:37

AW: Datei mit FileStream auslesen
 
@DeddyH,
ich denke, ich habe euren Rat befolgt. Jetzt sieht der code so aus :
.
.
.
Length_of_Reserve_string : array[1..32] of word;
.
.
.
Delphi-Quellcode:
for i:=1 to 32 do begin
  Read(ds.Length_of_Reserve_string[i],sizeof(word));
  SetLength(ds.Reserve_string[i], ds.Length_of_Reserve_string[i]);
  Read(ds.Reserve_string[i][1], ds.Length_of_Reserve_string[i]);
end;
Ist das so o.k. ? Könnte daraus ein Zugriff auf eine 'falsche'Speicheradresse erfolgen ?

tschüß

himitsu 30. Aug 2010 08:59

AW: Datei mit FileStream auslesen
 
@Deddy: Dich kann man aber auch leicht übersehn.
Oder gibt's hier doch eine verteckte und ausversehen aktivierte "Ignorierenfunktion"?

@delphinewbie:
Die Art der Änderung kommt auch mit auf die Datei an.
Wenn in der Datei nur 1 Byte drinsteht, dann hilft es nichts, wenn beim Auslesen nun alles einheitlich 2 Byte (Word) ist.

Ideal wäre es wirklich, wenn man nochmal alles komplett, inkl. einer Beispieldatei oder der Deklarantion der Speicherroutine sehn könnte.

Nachteule 30. Aug 2010 09:05

AW: Datei mit FileStream auslesen
 
Zitat:

Zitat von delphinewbie (Beitrag 1046014)
Hi,
danke für eure Tipps. Habe es umbenannt, nur ist das leider nicht mein Problem...
Ich möchte nochmal nachhaken : Ist TFilestream tatsächlich die einzige Variante, derartige Dateien auszulesen ?

tschüß

Delphi-Quellcode:
var
  myStringList : TStringList;
begin
  myStringlist := TStringList.Create;
  myStringList.LoadFromFile('bah.txt');
  // mach irgendwas
  ...

  myStringList.free;

DeddyH 30. Aug 2010 10:20

AW: Datei mit FileStream auslesen
 
So wie ich das Dateiformat verstanden habe kommst Du mit TStringlist nicht zum Ziel.

Nachteule 30. Aug 2010 12:27

AW: Datei mit FileStream auslesen
 
jetzt wäre halt interessant, wie das zu lesende File aussieht...

delphinewbie 31. Aug 2010 09:04

AW: Datei mit FileStream auslesen
 
Liste der Anhänge anzeigen (Anzahl: 2)
Guten Morgen,
tja , das zu lesende File hat eine ziemlich komplizierte Struktur. Es handelt sich hierbei um Dateien, die mittels eines Messverstärkers erstellt wurden.
Ich hänge mal die Beschreibung als PDF-Dokument an sowie eine Messwertdatei als Beispiel (3 Messkanäle mit je 36000 Werten).
Zusätzlich füge ich mal meine Struktur als Delphi-Code hinzu:
Delphi-Quellcode:
messwertdatei = record

// Global section
  FileID : word;
  data_offset : Longint;
  L_of_Filecomment : word;
  Filecomment : string;
  Length_of_Reserve_string : array[1..32] of word;
  Reserve_string : array[1..32] of string;
  NofChan : word;
  max_chan_length : Longint;
  offset_chan_length_entry : array[1..255] of longint;
  reduction_factor : Longint;

//Channel header section
  ch_location_in_database : array[1..255] of word;
  NVals : array[1..255] of longint;  //Anzahl der Meßwerte im jeweiligen Kanal
  str_length_ch_name : array[1..255] of word; //Länge Kanalname in Bytes
  ch_name : array[1..255] of string; //Kanalbezeichnung
  string_length_unit : array[1..255] of word;
  string_unit : array[1..255] of string; //Einheitenbezeichnung pro Kanal
  string_length_date : array[1..255] of word;
  string_date : array[1..255] of string; //Datum der Messung
  string_length_time : array[1..255] of word;
  string_time : array[1..255] of string; //Uhrzeit der Messung
  string_length_comment : array[1..255] of word;
  string_comment : array[1..255] of string; //Kommentar
  format : array[1..255] of word; //Datenformat : 0-numerisch, 1-string, 2-binär
  data_width : array[1..255] of word; //Datenbreite: numerisch-immer 8 Byte, string- >=8 Byte
  date_time : array[1..255] of double; //Datum,Zeit der Messung, neues Format
  size_ext_ch_header : array[1..255] of longint; //Größe des extended channel-header
  ext_ch_header : array[1..255] of string; //extended Channelheader muss noch
                                                // untersetzt werden, falls nötig
  lin_mode : array[1..255] of byte; //Linearisierungsmode
  user_scale_type :array[1..255] of byte;
  number_of_points_nScaleData : array[1..255] of byte;
  nScaleData : array[1..255] of double; //abhängig vom Skalierungstyp
  thermo_typ :array[1..255] of word;
  length_formula : array[1..255] of word;
  formula : array[1..255] of string; // Formel, wenn length_formula > 0
  size_sensor_info : array[1..255] of longint;
  sensor_info : array[1..255] of string; //sensor_info muss noch
                                                // untersetzt werden, falls Daten speziell benötigt werden
  end;
.. und nun wie ich die Datei auslese :
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var
i,j,s,z : integer;
b : byte;
export_format : integer;


begin
freearray;
zmax:=1; smax:=1;
dimArray(1,1);
with OpenDialog1 do
      begin
        DefaultExt := '.bin';
        Filter := 'Catman-Datei (*.bin)|*.bin';
        Title := 'Catman-datei oeffnen';
      end;
if OpenDialog1.Execute then
 begin
  f:=(TFileStream.Create(OpenDialog1.FileName,fmOpenRead));
  pfad:= OpenDialog1.FileName;
  Form2.Caption := pfad;    // Anzeige Dateipfad in Titelleiste des Formulars 2
  with f do begin
  Read(ds.FileID,sizeof(word));
  Read(ds.data_offset,sizeof(longint));
  Read(ds.L_of_Filecomment,sizeof(word));
  if ds.L_of_Filecomment <> 0 then
      Read(ds.Filecomment[1],ds.L_of_Filecomment);
  for i:=1 to 32 do begin
  Read(ds.Length_of_Reserve_string[i],sizeof(word));
  SetLength(ds.Reserve_string[i], ds.Length_of_Reserve_string[i]);
  Read(ds.Reserve_string[i][1], ds.Length_of_Reserve_string[i]);
  end;
  Read(ds.NofChan,sizeof(word));
  Read(ds.max_chan_length,sizeof(longint));
  for i:=1 to ds.NofChan do begin
      Read(ds.offset_chan_length_entry[i],sizeof(longint));
  end;
  Read(ds.reduction_factor,sizeof(longint));

 // Auslesen Channel-Header
  for i:=1 to ds.NofChan do begin
      Read(ds.ch_location_in_database[i],sizeof(word));
      Read(ds.NVals[i],sizeof(longint));

      Read(ds.str_length_ch_name[i],sizeof(word));
      SetLength(ds.ch_name[i], ds.str_length_ch_name[i]);
      Read(ds.ch_name[i][1],ds.str_length_ch_name[i]);


      Read(ds.string_length_unit[i],sizeof(word));
      SetLength(ds.string_unit[i], ds.string_length_unit[i]);
      Read(ds.string_unit[i][1],ds.string_length_unit[i]);


      if ds.FileID < 5009 then begin
      Read(ds.string_length_date[i],sizeof(word));
      SetLength(ds.string_date[i], ds.string_length_date[i]);
      Read(ds.string_date[i][1],ds.string_length_date[i]);

      Read(ds.string_length_time[i],sizeof(word));
      SetLength(ds.string_time[i], ds.string_length_time[i]);
      Read(ds.string_time[i][1],ds.string_length_time[i]);
      end;

      Read(ds.string_length_comment[i],sizeof(word));
      Setlength(ds.string_comment[i], ds.string_length_comment[i]);
      Read(ds.string_comment[i][1],ds.string_length_comment[i]);

      Read(ds.format[i],sizeof(word));
      Read(ds.data_width[i],sizeof(word));
      Read(ds.date_time[i],sizeof(double));
      Read(ds.size_ext_ch_header[i],sizeof(longint));
      Read(ds.ext_ch_header[i],ds.size_ext_ch_header[i]);
      Read(ds.lin_mode[i],sizeof(byte));
      Read(ds.user_scale_type[i],sizeof(byte));
      Read(ds.number_of_points_nScaleData[i],sizeof(byte));
      Read(ds.nScaleData[i],ds.number_of_points_nScaleData[i]*sizeof(double));
      Read(ds.thermo_typ[i],sizeof(word));
      Read(ds.length_formula[i],sizeof(word));
      if ds.length_formula[i]>0 then begin
        Setlength(ds.formula[i], ds.length_formula[i]);
        Read(ds.formula[i][1],ds.length_formula[i]);

      end;
      Read(ds.size_sensor_info[i],sizeof(longint));
      Setlength(ds.sensor_info[i], ds.size_sensor_info[i]);
      Read(ds.sensor_info[i][1],ds.size_sensor_info[i]);

  end;   //end for i:=1 to ds.NofChan

// Auslesen Data area

export_format := 0; //zum TEST :export_format wird 0 gesetzt, weil Messwerte hier als double abgespeichert sind und export_format noch nicht ausgewertet wird
if export_format = 0 then begin
    zmax:= ds.NofChan;
    smax:= ds.NVals[1];
    freearray;
    dimArray(zmax,smax);
    for s:=1 to ds.NofChan do
    for z:=1 to ds.NVals[1] do begin
        Read(wert,sizeof(double));
         wrA(s,z,wert);
      end;
   end; //end if export_format = 0

 end;    // end with f do
  f.Free;
end;      // if OpenDialog1.Execute

//Anzeige Messwerttabelle
form2.Show;

end;
... zur Vollständigkeit noch die anderen verwendeten Routinen...
Delphi-Quellcode:
type dArray = array[1..1] of Variant;

var
dA: ^dArray;

 procedure dimArray;        (* dyn. Speicher reservieren *)
 begin
  smax := s; zmax := z;
  GetMem(dA, SizeOf(dA^[1])* zmax * smax)
 end;

 procedure freeArray;      (* dyn. Speicher wieder freigeben *)
 begin
  FreeMem(dA,SizeOf(dA^[1])* zmax * smax)
 end;

 procedure wrA;            (* Schreibzugriff *)
 begin
  dA^[(z-1)* smax + s] := w
 end;
So, ich denke, ich habe alles wichtige nun gezeigt. Wenn ihr eine Lösungsidee habt, wäre ich euch unendlich dankbar. Die Fehlermeldung nach Programmende kann ja auf Dauer nicht sein !

P.S.: Oder kann es mit der Konfiguration Delphi7 und Vista zusammenhängen ?
Die Delphi-Hilfe läßt sich ja leider auch nicht installieren :pale:
Vielen Dank

shmia 31. Aug 2010 16:50

AW: Datei mit FileStream auslesen
 
Musst du die Datei bloss einlesen oder muss die Datei später auch verändert geschrieben werden?
Falls die Datei nur gelesen werden muss, könntest du Dir viel Arbeit sparen, wenn du eine Adapterklasse einsetzt.

Hier mal als Vergleich zwischen deiner alten Technik und meinem neuen Vorschlag:
Delphi-Quellcode:
Read(ds.FileID,sizeof(word)); // ALT
ds.FileID := h.ReadWord;     // NEU

// ALT - 3 Zeilen
Read(ds.string_length_comment[i],sizeof(word));
Setlength(ds.string_comment[i], ds.string_length_comment[i]);
Read(ds.string_comment[i][1],ds.string_length_comment[i]);

// NEU - nur eine Zeile
ds.string_length_comment[i] := h.ReadShortString;
Beim Einlesen eines Words ist der Unterschied noch recht gering,
aber beim Einlesen von den Strings zeigt sich doch, dass die neue Technik viel angenehmer ist.

Ausserdem kannst du Dir damit sämtliche Längenangaben in dem Record sparen
und dich voll auf die Nutzdaten konzentrieren.

Hier wäre mal die Deklaration der Adapterklasse:
Delphi-Quellcode:
  TStreamAdapter = class(TObject)
  protected
    FStream : TStream;
  public
    constructor Create(AStream:TStream;AOwnsStream: Boolean = False);
    destructor Destroy;override;
    function ReadBoolean: Boolean;
    function ReadChar: Char;
    function ReadCurrency: Currency;
    function ReadDateTime: TDateTime;
    function ReadDouble: Double;
    function ReadExtended: Extended;
    function ReadInt64: Int64;
    function ReadInteger: Integer;
    function ReadCString: string;
    function ReadShortString: string;
    function ReadSingle: Single;
    function ReadSizedString: string;
    function ReadWord:Word;
    procedure WriteBoolean(Value: Boolean);
    procedure WriteChar(Value: Char);
    procedure WriteCurrency(const Value: Currency);
    procedure WriteDateTime(const Value: TDateTime);
    procedure WriteDouble(const Value: Double);
    procedure WriteExtended(const Value: Extended);
    procedure WriteInt64(Value: Int64); overload;
    procedure WriteInteger(Value: Integer); overload;
    procedure WriteStringDelimitedByNull(const Value: string);
    procedure WriteShortString(const Value: ShortString);
    procedure WriteSingle(const Value: Single);
    procedure WriteSizedString(const Value: string);
    procedure WriteWord(const Value:Word);
  end;
Bei Interesse kann ich dir noch mehr zu der Adapterklasse schreiben.

delphinewbie 2. Sep 2010 06:42

AW: Datei mit FileStream auslesen
 
Hi shmia,
vielen Dank für deinen Vorschlag. Ja, die Datei muss nur ausgelesen werden. Veränderungen daran sind sogar unerwünscht !!!
Muss leider zugeben, dass ich mit Adapterklassen nichts anfangen kann, da ich ja auch erst anfange, mich mit delphi zu beschäftigen. Eins ist mir jedoch an deinem Beispiel aufgefallen :
Delphi-Quellcode:
// NEU - nur eine Zeile
ds.string_length_comment[i] := h.ReadShortString;
Ich lese doch eigentlich zwei Werte aus: 1. Länge der folgenden Zeichenkette - 2. Zeichenkette selbst

Bei dir in der einen Zeile kann ich aber nur erkennen, dass die Länge der Zeichenkette ausgelesen wird. Mir ist jetzt nicht klar, wie deine eine Zeile meine drei Zeilen ersetzt.

Auch wenn ich mir dadurch 'ne Menge Arbeit ersparen würde, stellt sich mir aber die Frage, ob damit der Fehler behoben wäre, der nach jedem Programmende auftritt.
Ich gehe bisher davon aus, dass das Auslesen der Datei richtig funktioniert, weil auch die korrekten Kurven usw. entstehen. Nur muss halt danach noch etwas unsauber programmiert sein (fehlende Speicherfreigaben oder ungültige Speicherbereiche...)
Ich habe die Hoffnung noch nicht aufgegeben, das Problem zu lösen und setze auch weiterhin ganz stark auf euer immenses Wissen :wink:
Tschüß und :hi:

himitsu 2. Sep 2010 07:00

AW: Datei mit FileStream auslesen
 
Er meinte es wohl eher so
Delphi-Quellcode:
ds.string_comment[i] := h.ReadShortString;
.
bzw. so
Delphi-Quellcode:
ds.string_comment[i] := h.ReadShortString;
ds.string_length_comment[i] := Length(ds.string_comment);
Das ReadShortString ließt wohl das LängenByte aus und darauf folgend entsprechend viele Bytes/AnsiZeichen in einen String, welcher dann zurückgegeben wird.


PS: Nur um die Verwirrungen komplett zu machen.
Man ließt hier eine feste Anzahl an Byte in einen String,
nur daß ab Delphi 2009 der String ein UnicodeString ist und somit jedes Zeichen darin 2 Byte groß wäre.
Und dann behaupte man wieder ich hätte nie davor gewarnt, daß man keine generischen Typen (wie den String) mit festen ByteGrößen gleichsetzen soll.

delphinewbie 2. Sep 2010 08:54

AW: Datei mit FileStream auslesen
 
Hi,
das würde heißen, wenn ich die Stringlänge eigentlich nicht weiter benötige, genügt diese Zeile

ds.string_comment[i] := h.ReadShortString; ?

Funzt das nur, wenn die Stringlänge in einem Byte steht ? Was ist, wenn die Länge aber in 2 Bytes steht, wie bei mir ?

L_of_Filecomment : word;
Filecomment : string;

Zitat:

PS: Nur um die Verwirrungen komplett zu machen.
Das hat auf jeden Fall geklappt !!!:wink:

Ich glaube, ich laß lieber die Finger davon... Es muss auch mit FileStream gehen, wenn auch mit etwas mehr Aufwand.

himitsu 2. Sep 2010 09:16

AW: Datei mit FileStream auslesen
 
Zitat:

Zitat von delphinewbie (Beitrag 1046906)
Funzt das nur, wenn die Stringlänge in einem Byte steht ? Was ist, wenn die Länge aber in 2 Bytes steht, wie bei mir ?

Wenn diese Funktion so erstellt wurde, daß sie mit 2 Byte als Länte arbeitet, dann kann man es auch nehmen.

Und genau deswegen hatte ich doch schonmal gefragt.
Diese 2 Byte sind auch in der Datei vorhanden und nicht nur in der Record-Deklaration?

Nja, selbst wenn du die länge selber ausließt, muß sie nicht unbegingt mit in dem Record drinstehn.

Zitat:

Zitat von delphinewbie (Beitrag 1046906)
Ich glaube, ich laß lieber die Finger davon... Es muss auch mit FileStream gehen, wenn auch mit etwas mehr Aufwand.

Auch bei dem FileStream mußt du aufpassen.
Deklariere einfach deine Strings als AnsiString und gut ist.

Du kannst gerne mal so ab etwa hier ( http://www.delphipraxis.net/154168-n...ml#post1046616 ) dir die unicode- und integerbezogenen Postings durchlesen.

delphinewbie 2. Sep 2010 10:28

AW: Datei mit FileStream auslesen
 
Jawoll,
diese zwei Bytes sind in der Datei vorhanden. Ich muss immer wieder darauf hinweisen : Das Auslesen der Datei funktioniert. Wäre die Dateilänge bspw. nur in einem Byte abgelegt statt wie von mir angenommen in zweien, müßte es doch bei der Darstellung der Daten (z.B. in einer Tabelle) ein riesen Durcheinander geben. Zusätzlich habe ich noch den Vergleich mit einer Textdatei, die durch das Programm, mit dem die Messwerte gewonnen werden aus der Binärdatei konvertiert wird. Und ich muss sagen, dass ich hier eine exakte Übereinstimmung feststellen kann.
Nun werde ich trotzdem mal auf AnsiString umstellen, vllt. bewirkt es ja was....

p80286 2. Sep 2010 12:31

AW: Datei mit FileStream auslesen
 
Entschuldigt,
aber wenn ich soetwas als Beschreibung von Daten in einer Datei lese, fühle ich mich doch sehr unwohl:
Delphi-Quellcode:
formula : array[1..255] of string;
was verbirgt sich hinter "String"?
Handelt es sich um den "klassischen" Pascal-String Längenbyte,Nutzdaten[1]..Nutzdaten[längenbyte] oder ist es ein LängenWort(16Bit)/(32Bit), sind für jeden String 255 Bytes reserviert oder sind die Längenangaben/Strings mit oder ohne Trennzeichen hintereinander "geklatscht"??????
Unicode und 16Bit-Chars sparen wir uns einmal.

Und dann gibt es noch die Frage ob die Zahlen Leastsignifikant (Intel) gespeichert wurden, denn wenn dies nicht der Fall ist, dann kann man kein Word/Integer oder was auch immer sondern nur Bytes lesen, die dann erst einmal "richtig" sortiert werden müssen.

(Falls man das Format einer Datei nicht genau kennt, dann geht kein Weg an Filestream vorbei)

Gruß
K-H

mkinzler 2. Sep 2010 12:33

AW: Datei mit FileStream auslesen
 
In einem Record sollte/darf man nur ShortString verwenden

p80286 2. Sep 2010 16:17

AW: Datei mit FileStream auslesen
 
Zitat:

Zitat von mkinzler (Beitrag 1046970)
In einem Record sollte/darf man nur ShortString verwenden

"sollte" kann ich nur voll unterstützen,
bei "darf" hab' ich so meine Zweifel. Wenn ich mich richtig erinnere geistern hier einige Records mit AnsiStrings herum.

Gruß
K-H

mkinzler 2. Sep 2010 16:25

AW: Datei mit FileStream auslesen
 
Man kann es schon verwenden. Eine solche Struktur kann man dann aber nicht in typisierten Datein o.ä. verwenden

delphinewbie 10. Sep 2010 10:57

Problem gelöst
 
Hi,
nach unendlich vielen Versuchen bin ich nun zu einer Lösung meines Problems gekommen. Auch wenn ich nicht ganz nachvollziehen kann, wo letztendlich der Unterschied dieser beiden Varianten besteht, bin ich nun erstmal erleichtert, dass der Fehler beim Programm beenden nicht mehr auftritt. Vielleicht kann mir von euch jemand erklären, wo hier der feine Unterschied liegt.
Also: meine ursprüngliche Variante
Delphi-Quellcode:
Read(ds.size_ext_ch_header[i],sizeof(longint));
Setlength(ds.ext_ch_header[i], ds.size_ext_ch_header[i]);
Read(ds.ext_ch_header[i],ds.size_ext_ch_header[i]);
habe ich nun verändert in
Delphi-Quellcode:
Read(ds.size_ext_ch_header[i],sizeof(longint));
for k:=1 to ds.size_ext_ch_header[i] do
     Read(ds.ext_ch_header[i],1);
Es wird nun also byteweise ausgelesen, und zwar so oft, wie es in ds.size_ext_ch_header[i] drin steht. Und es funktioniert :thumb:
Da ich den Inhalt dieser Bytes nicht weiter benötige, kann ich also diese auch immer wieder überschreiben.
Kann ich eigentlich in so einem Fall auch einfach 100 Byte oder so viel Bytes, wie in ds.size_ext_ch_header[i] steht, weiter springen, um so bspw. 'uninteressante' Daten zu überspringen ? Dann könnte ich mir ja diese for-Schleife sparen...

Vielen Dank für Eure Tipps

shmia 10. Sep 2010 11:10

AW: Datei mit FileStream auslesen
 
Du kannst Daten, die du nicht braucht ganz einfach so überspringen:
Delphi-Quellcode:
Position := Position + 100; // aktuelle Position im Stream um 100 Bytes nach "hinten" verschieben.

himitsu 10. Sep 2010 11:25

AW: Datei mit FileStream auslesen
 
Zitat:

Zitat von shmia (Beitrag 1048659)
Delphi-Quellcode:
Position := Position + 100;

Oder man nehme .Seek :angel:

delphinewbie 10. Sep 2010 11:28

AW: Datei mit FileStream auslesen
 
Sooooo einfach kann es sein !!!
Hat geklappt,
Danke


Alle Zeitangaben in WEZ +1. Es ist jetzt 12:40 Uhr.

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