![]() |
AW: Datei mit FileStream auslesen
Zitat:
Delphi-Quellcode:
var
myStringList : TStringList; begin myStringlist := TStringList.Create; myStringList.LoadFromFile('bah.txt'); // mach irgendwas ... myStringList.free; |
AW: Datei mit FileStream auslesen
So wie ich das Dateiformat verstanden habe kommst Du mit TStringlist nicht zum Ziel.
|
AW: Datei mit FileStream auslesen
jetzt wäre halt interessant, wie das zu lesende File aussieht...
|
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:
.. und nun wie ich die Datei auslese :
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;
Delphi-Quellcode:
... zur Vollständigkeit noch die anderen verwendeten Routinen...
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;
Delphi-Quellcode:
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 !
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; 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 |
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:
Beim Einlesen eines Words ist der Unterschied noch recht gering,
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; 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:
Bei Interesse kann ich dir noch mehr zu der Adapterklasse schreiben.
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; |
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:
Ich lese doch eigentlich zwei Werte aus: 1. Länge der folgenden Zeichenkette - 2. Zeichenkette selbst
// NEU - nur eine Zeile
ds.string_length_comment[i] := h.ReadShortString; 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: |
AW: Datei mit FileStream auslesen
Er meinte es wohl eher so
Delphi-Quellcode:
.
ds.string_comment[i] := h.ReadShortString;
bzw. so
Delphi-Quellcode:
Das ReadShortString ließt wohl das LängenByte aus und darauf folgend entsprechend viele Bytes/AnsiZeichen in einen String, welcher dann zurückgegeben wird.
ds.string_comment[i] := h.ReadShortString;
ds.string_length_comment[i] := Length(ds.string_comment); 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. |
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:
Ich glaube, ich laß lieber die Finger davon... Es muss auch mit FileStream gehen, wenn auch mit etwas mehr Aufwand. |
AW: Datei mit FileStream auslesen
Zitat:
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:
Deklariere einfach deine Strings als AnsiString und gut ist. Du kannst gerne mal so ab etwa hier ( ![]() |
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.... |
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:20 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz