Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   EReadError beim Lesen der mit TWriter geschriebenen Daten (https://www.delphipraxis.net/186109-ereaderror-beim-lesen-der-mit-twriter-geschriebenen-daten.html)

DualCoreCpu 4. Aug 2015 10:30

EReadError beim Lesen der mit TWriter geschriebenen Daten
 
Hallo,

es geht immer noch um TReader/TWriter. Gestern hatte ich hier:
http://www.delphipraxis.net/186096-e...er-stream.html

Daten geschrieben, die ich nun lesen will. Dabei erhalte ich die EReadError Exception.

Das hier ist der aktuelle Quelltext dazu:

Delphi-Quellcode:
unit Unit1;

interface

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

type
  TTestRec = record
    Feld1: String;
    Feld2: String;
    Feld3: String;
  end;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    btnOk: TButton;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Memo: TMemo;
    procedure FormDestroy(Sender: TObject);
    procedure Edit1Change(Sender: TObject);
    procedure Edit2Change(Sender: TObject);
    procedure Edit3Change(Sender: TObject);
    procedure btnOkClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    FStream: TFileStream;
    FReader: TFileStream;
    FileReader: TReader;
    FFileWriter: TWriter;
    FTestFields: TTestRec;
  public
    { Public declarations }
    procedure CreateFileForWrite;
    procedure CreateWnd; override;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.btnOkClick(Sender: TObject);
begin
  FFileWriter.WriteString(FTestFields.Feld1);
  FFileWriter.WriteString(FTestFields.Feld2);
  FFileWriter.WriteString(FTestFields.Feld3);
end;

procedure TForm1.CreateFileForWrite;
var
  Directory: String;
begin
  Directory := GetCurrentDir;
  if Directory[Length(Directory)]<>'\' then Directory := Directory + '\';
  FStream := TFileStream.Create(Directory+'Testfile.def', fmCreate);
  FFileWriter := TWriter.Create(FStream,1024);
end;

procedure TForm1.Edit1Change(Sender: TObject);
begin
  FTestFields.Feld1 := Edit1.Text;
end;

procedure TForm1.Edit2Change(Sender: TObject);
begin
  FTestFields.Feld2 := Edit2.Text;
end;

procedure TForm1.Edit3Change(Sender: TObject);
begin
  FTestFields.Feld3 := Edit3.Text;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  FFileWriter.Free;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  //Erzeugen des Streams zum Lesen
  FReader := TFileStream.Create('TestFile.def', fmOpenRead, fmShareDenyWrite);

  //Erzeugen des Filereader Objektes vom Typ TReader
  FileReader := TReader.Create(FReader, 1024);

  //Lesen der Daten
  FTestFields.Feld1 := FileReader.ReadString;
  FTestFields.Feld2 := FileReader.ReadString;
  FTestFields.Feld3 := FileReader.ReadString;

  FileReader.Free; //Zunächst Reader freigeben und so Datei schließen

  CreateFileForWrite; //Nun kann die Datei zum Schreiben geöffnet werden.

  //Überprüfen, ob richtig gelesen
  Memo.Lines.Add('Feld 1 ---> '+FTestFields.Feld1);
  Memo.Lines.Add('Feld 2 ---> '+FTestFields.Feld2);
  Memo.Lines.Add('Feld 3 ---> '+FTestFields.Feld3);

end;

procedure TForm1.CreateWnd;
begin
  inherited;
  //CreateFileForWrite;
  //Diese Methode wird VOR FormCreate aufgerufen. Damit wird die Datei von anderem Prozess
  //verwendet, ich erhalte eine EFOpenError Exception. Deshalb in FormCreate verlegt.
end;

end.
Meine Frage ist nun, wie kann ich das Lesen bewerkstelligen?

baumina 4. Aug 2015 10:37

AW: EReadError beim Lesen der mit TWriter geschriebenen Daten
 
Dateiname ohne Pfadangebe vielleicht?

DualCoreCpu 4. Aug 2015 10:50

AW: EReadError beim Lesen der mit TWriter geschriebenen Daten
 
Zitat:

Zitat von baumina (Beitrag 1310895)
Dateiname ohne Pfadangebe vielleicht?

Nein, leider nicht die Ursache. Wenn ich vor

Delphi-Quellcode:
  FReader := TFileStream.Create(...);
das hier ergänze:

Delphi-Quellcode:
  Directory := GetCurrentDir;
  if Directory[Length(Directory)]<>'\' then Directory := Directory + '\';
  FReader := TFileStream.Create(Directory + 'Testfile.def', fmOpenRead, fmShareDenyWrite);
erhalte ich dieselbe EFReadError Exception.

Was also kann ich noch tun?

Klaus01 4. Aug 2015 10:54

AW: EReadError beim Lesen der mit TWriter geschriebenen Daten
 
Lass Dir doch das Verzeichnis mal ausgeben.
Oder setze einen Haltepunkt und schau es dir im Debugger an.

Grüße
Klaus

Luckie 4. Aug 2015 10:59

AW: EReadError beim Lesen der mit TWriter geschriebenen Daten
 
Welche R+ückgabe erwartest du von GetCurrentDirectory? Tipp: es muss nicht zwingend das Verzeichnis deiner Anwendung sein.

p80286 4. Aug 2015 11:56

AW: EReadError beim Lesen der mit TWriter geschriebenen Daten
 
Zitat:

Zitat von Luckie (Beitrag 1310905)
Welche R+ückgabe erwartest du von GetCurrentDirectory? Tipp: es muss nicht zwingend das Verzeichnis deiner Anwendung sein.

Da er auch beim Schreiben mit
Delphi-Quellcode:
GetCurrentDirectory
hantiert, augenscheinlich eine verlässliche Information.

@dualCoreCpu
Delphi-Quellcode:
GetCurrentDirectory
ist genauso zuverlässig wie relative Pfadangaben, und sobald auch nur ganz kurz "das passiert sowieso nicht" bei der Überlegung ob etwas schief gehen kann, aufblitzt, dann geht das garantiert schief.
Entweder du nutzt selbst definierte Pfadangaben oder (meiner Meinung nach besser), du nutzt die Windows-Standardverzeichnisse.

Gruß
K-H

DualCoreCpu 4. Aug 2015 11:59

AW: EReadError beim Lesen der mit TWriter geschriebenen Daten
 
Zitat:

Zitat von Luckie (Beitrag 1310905)
Welche R+ückgabe erwartest du von GetCurrentDirectory? Tipp: es muss nicht zwingend das Verzeichnis deiner Anwendung sein.

Upps, wieso das nicht?

Von GetCurrentDir aud dem Hauptprogramm aufegerufen wewarte ich jenes Verzeichnis, in welchem meine Anwendung liegt.

Hab es jetzt so gemacht:

Directory := IncludeTrailingPathDelimiter(ExtractFilePath(Param str(0)));

führt aber nicht zm gewünschten Erfolg. Die EReadError Exception kommt immer noch.

Luckie 4. Aug 2015 12:06

AW: EReadError beim Lesen der mit TWriter geschriebenen Daten
 
Das sagt doch schon der Name: "Gib das aktuelle Verzeichnis zurück". Einmal einen Open- oder Savedialog benutzt und dabei das Verzeichnis gewechselt, schon ist das aktuelle Verzeichnis nicht mehr das Anwendungsverzeichnis. Wenn du das Anwendungsverzeichnis willst, dann guck dir in der Hilfe mal ParamStr an. Davon mal abgesehen, dass es eine ganz schlechte Idee ist irgendwelche Dateien die auch geschrieben werden sollen im Anwendunsgverzeichnis abzulegen. Da dort nur Benutzer der Administratorengruppe schreiben können. Und wen du es anders einrichtest, überschreiben sich die verschiedenen Benutzer gegenseitig die Datei.

DualCoreCpu 4. Aug 2015 12:17

AW: EReadError beim Lesen der mit TWriter geschriebenen Daten
 
Um weiteren Zwischenfragen vorzubeugen:

Die Datei aus der ich lesen will, existiert im Pfad und enthält auch Strings, die ich nun auslesen will.

Das Format ist

Byte
0 Inhalt $06 vermulich eine Signatur, denn dieses Byte steht vor hedem String.

1 Längenbyte obwohl Ansistrings geschrieben werden können, lt. Hilfe, gibt es nur ein
Längenbyte.

2-... der String

Danach die gleiche Abfolge -> SIgnatur, Längenbyte, String. Bis Dateiende. Am Dateiende steht das letzte Zeichen des letzten Strings.

baumina 4. Aug 2015 12:21

AW: EReadError beim Lesen der mit TWriter geschriebenen Daten
 
Wie heißt die Fehlermeldung genau und in welcher Zeile tritt sie auf?

DualCoreCpu 4. Aug 2015 12:26

AW: EReadError beim Lesen der mit TWriter geschriebenen Daten
 
Zitat:

Zitat von Luckie (Beitrag 1310923)
Das sagt doch schon der Name: "Gib das aktuelle Verzeichnis zurück". Einmal einen Open- oder Savedialog benutzt und dabei das Verzeichnis gewechselt, schon ist das aktuelle Verzeichnis nicht mehr das Anwendungsverzeichnis. Wenn du das Anwendungsverzeichnis willst, dann guck dir in der Hilfe mal ParamStr an. Davon mal abgesehen, dass es eine ganz schlechte Idee ist irgendwelche Dateien die auch geschrieben werden sollen im Anwendunsgverzeichnis abzulegen. Da dort nur Benutzer der Administratorengruppe schreiben können. Und wen du es anders einrichtest, überschreiben sich die verschiedenen Benutzer gegenseitig die Datei.

Ok, danke für den Hinweis. Werd ich bei praktischen Anwendungen beherzigen.

Open und Savedialog verwende ich in meinem Testprogramm nicht, aber das könnte in einer praktischen Anwendung natürlich schnell passieren. Dort werd ich wohl dann ein für Anwendungs bzw. Konfigurationsdaten ein eigenes Verzeichnis einrichten.

Zitat:

Zitat von baumina
Wie heißt die Fehlermeldung genau und in welcher Zeile tritt sie auf?

Die Meldung lautet 'Stream Lesefehler' und tritt beim ersten ReadString auf.

Delphi-Quellcode:
  FTestFields.Feld1 := FileReader.ReadString;

.

Luckie 4. Aug 2015 12:38

AW: EReadError beim Lesen der mit TWriter geschriebenen Daten
 
Zitat:

Zitat von DualCoreCpu (Beitrag 1310932)
Die Datei aus der ich lesen will, existiert im Pfad und enthält auch Strings, die ich nun auslesen will.

Das stellt ja auch keine rin Abrede. Nur guckt deine Anwendung auch im richtigen Pfad? Das ist doch die Frage. Stell das erst mal sicher. Dann können wir weitersehen.

Klaus01 4. Aug 2015 12:39

AW: EReadError beim Lesen der mit TWriter geschriebenen Daten
 
vielleicht hilft diese Routine:

Delphi-Quellcode:
procedure TCustomSettings.LoadFromStream(const Stream: TStream) ;
 var
   Reader: TReader;
   PropName, PropValue: string;
 begin
   Reader := TReader.Create(Stream, $FFF) ;
   Stream.Position := 0;
   Reader.ReadListBegin;
 
   while not Reader.EndOfList do
   begin
     PropName := Reader.ReadString;
     PropValue := Reader.ReadString;
     SetPropValue(Self, PropName, PropValue) ;
   end;
 
   FreeAndNil(Reader) ;
 end;
Quelle

Grüße
Klaus

Uwe Raabe 4. Aug 2015 13:20

AW: EReadError beim Lesen der mit TWriter geschriebenen Daten
 
Zitat:

Zitat von DualCoreCpu (Beitrag 1310932)
Byte
0 Inhalt $06 vermulich eine Signatur, denn dieses Byte steht vor hedem String.

1 Längenbyte obwohl Ansistrings geschrieben werden können, lt. Hilfe, gibt es nur ein
Längenbyte.

2-... der String

Danach die gleiche Abfolge -> SIgnatur, Längenbyte, String. Bis Dateiende. Am Dateiende steht das letzte Zeichen des letzten Strings.

Das sieht schonmal ganz gut aus. Die 6 ist die Kennung für einen AnsiString bis 255 Zeichen Länge. Es gibt noch AnsiStrings mit mehr als 255 Zeichen, UTF8-Strings und Unicode-Strings, jeweils mit anderen Signaturen. Das WriteString entscheidet allein vom Inhalt des Strings, welches das geeignete Stringformat ist. ShortStrings gibt es dort nicht.

Uwe Raabe 4. Aug 2015 13:24

AW: EReadError beim Lesen der mit TWriter geschriebenen Daten
 
Zitat:

Zitat von Klaus01 (Beitrag 1310944)
vielleicht hilft diese Routine:

Wohl kaum! Das würde voraussetzen, daß die Daten auch in diesem Format abgespeichert wurden, was hier aber nicht der Fall ist.

@DualCoreCpu: Kannst du die Datei einfach mal hier anhängen? Dann kann auch mal jemand anders versuchen, die einzulesen.

DualCoreCpu 4. Aug 2015 13:50

AW: EReadError beim Lesen der mit TWriter geschriebenen Daten
 
Zitat:

Zitat von Klaus01 (Beitrag 1310944)
vielleicht hilft diese Routine:

Delphi-Quellcode:
procedure TCustomSettings.LoadFromStream(const Stream: TStream) ;
 var
   Reader: TReader;
   PropName, PropValue: string;
 begin
   Reader := TReader.Create(Stream, $FFF) ;
   Stream.Position := 0;
   Reader.ReadListBegin;
 
   while not Reader.EndOfList do
   begin
     PropName := Reader.ReadString;
     PropValue := Reader.ReadString;
     SetPropValue(Self, PropName, PropValue) ;
   end;
 
   FreeAndNil(Reader) ;
 end;
Quelle

Grüße
Klaus

Danke Dir, so funktioniert es. Habe eine äquivalente SaveToStream Methode dazu geschrieben.

Es hat allerdings nicht sofort funktioniert, das Lesen schon aber anschließendens Schreiben nicht. EFOpenError für den Writer.

Die Ursache dafür war:

Der Stream wird mit FreeAndNil(Reader) nicht mit frei gegeben. Dies muss mit

Stream.Free nach FreeAndNil(Reader) separat erfolgen.

Dann funktioniert auch das Schreiben in die Datei danach.

DualCoreCpu 4. Aug 2015 14:05

AW: EReadError beim Lesen der mit TWriter geschriebenen Daten
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von Uwe Raabe (Beitrag 1310957)
Zitat:

Zitat von Klaus01 (Beitrag 1310944)
vielleicht hilft diese Routine:

Wohl kaum! Das würde voraussetzen, daß die Daten auch in diesem Format abgespeichert wurden, was hier aber nicht der Fall ist.

@DualCoreCpu: Kannst du die Datei einfach mal hier anhängen? Dann kann auch mal jemand anders versuchen, die einzulesen.

Ok, will es versuchen. Obwohl Endung .txt, ist es keine reine Textdatei, nur meine ursprüngliche Dateiendung .def akzeptiert der hiesige Uploader nicht.

Um die LoadFromStream() Methode von @Klaus einsetzen zu können, musste ich die Testdaten unter Deaktivierung der Lesemethode nochmals schreiben.

Vorher fehlte das Listenendezeichen $00 und das ListBegin Zeichen $01. Alles andere (Kennzeichnung $06 und Längenbyte vor dem String, dann der eigentliche String, war schon vorher da.

Das hier sind jetzt die wesentlichen Änderungen:

Delphi-Quellcode:
procedure TForm1.btnOkClick(Sender: TObject);
var Directory: String;
begin
  Directory := GetCurrentDir;
  if Directory[Length(Directory)]<>'\' then Directory := Directory + '\';
  FStream := TFileStream.Create(Directory+'Testfile.def', fmCreate);
  SaveToStream(FStream);
  { So hatte ich es vorher
  FFileWriter.WriteListBegin;
  FFileWriter.WriteString(FTestFields.Feld1);
  FFileWriter.WriteString(FTestFields.Feld2);
  FFileWriter.WriteString(FTestFields.Feld3);
  FFileWriter.WriteListEnd;
  }
end;
Hier FormCreate:

Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
var Directory: String;
begin
  //Erzeugen des Streams zum Lesen
  Directory := IncludeTrailingPathDelimiter(ExtractFilePath(Paramstr(0)));
  //ShowMessage(Directory); wird richtig angezeigt.

  FReader := TFileStream.Create(Directory+'TestFile.def', fmOpenRead, fmShareDenyWrite);

  //Lesen der Daten
  LoadFromStream(FReader);

  //Überprüfen, ob richtig gelesen
  Edit1.Text := FTestFields.Feld1;
  Edit2.Text := FTestFields.Feld2;
  Edit3.Text := FTestFields.Feld3;
  //Inhalt stimmt anschließend
end;
und hier die Lese- und Schreibmethode:

Delphi-Quellcode:
procedure TForm1.LoadFromStream(const Stream: TStream);
var Reader: TReader;
begin
  Reader := TReader.Create(Stream, $0FFF);
  Reader.ReadListBegin;
  while not Reader.EndOfList do
  begin
  FTestFields.Feld1 := Reader.ReadString;
  FTestFields.Feld2 := Reader.ReadString;
  FTestFields.Feld3 := Reader.ReadString;
  end;
  FreeAndNil(Reader);
  Stream.Free; //sonst EfOpenError beim nächsten Öffnen für Schreiben!!!
end;

procedure TForm1.SaveToStream(const Stream: TStream);
var
  Writer: TWriter;
begin
  Writer := TWriter.Create(Stream, $0FFF);
  Writer.WriteListBegin;
  Writer.WriteString(Edit1.Text);
  Writer.WriteString(Edit2.Text);
  Writer.WriteString(Edit3.Text);
  Writer.WriteListEnd;
  FreeAndNil(Writer);
  Stream.Free;
end;
Mit diesen Methoden funktioniert es jetzt. Danke wie verrückt Euch allen! :)))))

P.S. Wollte eigentlich nen schönen Smilie eifügen, geht aber beim Nachbearbeiten nicht. :( schade!

DualCoreCpu 4. Aug 2015 14:17

AW: EReadError beim Lesen der mit TWriter geschriebenen Daten
 
Zitat:

Zitat von Luckie (Beitrag 1310943)
Zitat:

Zitat von DualCoreCpu (Beitrag 1310932)
Die Datei aus der ich lesen will, existiert im Pfad und enthält auch Strings, die ich nun auslesen will.

Das stellt ja auch keine rin Abrede. Nur guckt deine Anwendung auch im richtigen Pfad? Das ist doch die Frage. Stell das erst mal sicher. Dann können wir weitersehen.

Doch das tut sie. :)

Wollte mit der Meldung, Datei ist da nur Zwischenfragen vorbeugen die die Antwort verzögern. Obwohl schon klar ist, das auch der Pfad stimmen muss, worauf ich zukünftig auch besonders achten werde! :))))

Bisher habe ich das als selbstverstädlich vorausgesetzt, jetzt besser nicht mehr, obwohl es hier funktioniert hat und nicht die Ursache für mein Problem war.


Alle Zeitangaben in WEZ +1. Es ist jetzt 13:38 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-2025 by Thomas Breitkreuz