Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Versuch hinter dem Dateiende zu lesen (https://www.delphipraxis.net/33327-versuch-hinter-dem-dateiende-zu-lesen.html)

TheMiller 4. Nov 2004 21:32


Versuch hinter dem Dateiende zu lesen
 
Hey, stehe auf dem Schlauch. wo ist der Fehler?

Delphi-Quellcode:
procedure TForm1.FillList;
var
  i:Integer;
begin
  for i:=0 to sizeof(datei) do begin
   Seek(datei, i);
   Read(datei, data);
   ListView1.Items.Add;
   ListView1.Items[i].Caption:=data.Name;
   with ListView1.Items[i].SubItems do begin
    Add(data.Format);
    Add(data.Sprache);
   end;
  end;
end;
Initialisiert wird so:

Delphi-Quellcode:
procedure TForm1.FormCreate(Sender: TObject);
begin
  AssignFile(datei, 'index.dat');
  IF FileExists('index.dat') THEN Reset(datei)
  else Rewrite(datei);

  filllist;
end;
Fehlermeldung: Versuch hinter dem Dateieinde zu lesen. Könnte ja einen try-except Block einbauen, aber das ist nicht so die feine Art...

Bitte somit jämmerlich um Hilfe! :-D

alcaeus 4. Nov 2004 21:39

Re: Versuch hinter dem Dateiende zu lesen
 
Hi DJ-SPM,

der Fehler liegt eindeutig hier:
Delphi-Quellcode:
for i:=0 to sizeof(datei) do begin
sizeof(datei) gibt dir die Anzahl Datensätze in der Datei zurück. Nachdem die Indizierung bei 0 und nicht bei 1 beginnt, hört sie auch bei sizeof(datei)-1 auf.

Greetz
alcaeus

TheMiller 4. Nov 2004 21:41

Re: Versuch hinter dem Dateiende zu lesen
 
Also, ich finde es cool, dass dumir heute so viel hilfst, aber sizeof(datei)-1 bringt den gleichen Fehler...

alcaeus 4. Nov 2004 21:43

Re: Versuch hinter dem Dateiende zu lesen
 
Hi DJ-SPM,

in welcher Zeile steht der Cursor sobald die Exception auftritt? in deinem Code sehe ich nämlich keinen weiteren Fehler.

Greetz
alcaeus

TheMiller 4. Nov 2004 21:46

Re: Versuch hinter dem Dateiende zu lesen
 
Delphi-Quellcode:
procedure TForm1.FillList;
var
  i:Integer;
begin
  for i:=0 to sizeof(datei)-1 do begin
   Seek(datei, i);
   Read(datei, data); <---------------HIER
   ListView1.Items.Add;
   ListView1.Items[i].Caption:=data.Name;
   with ListView1.Items[i].SubItems do begin
    Add(data.Format);
    Add(data.Sprache);
   end;
  end;
end;
Hier mal mein Programmcode:

Delphi-Quellcode:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Buttons, XPMan, ComCtrls;

type
  TForm1 = class(TForm)
    ListView1: TListView;
    GroupBox1: TGroupBox;
    XPManifest1: TXPManifest;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    Label5: TLabel;
    Label6: TLabel;
    GroupBox2: TGroupBox;
    BitBtn1: TBitBtn;
    Label7: TLabel;
    Edit1: TEdit;
    Edit2: TEdit;
    Edit3: TEdit;
    Edit4: TEdit;
    Edit5: TEdit;
    Edit6: TEdit;
    Edit7: TEdit;
    Label8: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure BitBtn1Click(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure ListView1Click(Sender: TObject);
  private
    procedure FillList;
    procedure OpenInfo;
  public
    { Public-Deklarationen }
  end;

  TMovie = record
   Name    :string[150];
   Format  :string[100];
   CDs     :string[1];
   Ton     :string[20];
   Bild    :string[20];
   Sprache :string[20];
   Gernre  :string[20];
   Kommentar:string[255];
  end;

var
  Form1 : TForm1;
  datei : file of TMovie;
  data : TMovie;

implementation

{$R *.dfm}

procedure TForm1.FillList;
var
  i:Integer;
begin
  for i:=0 to sizeof(datei)-1 do begin
   Seek(datei, i);
   Read(datei, data);
   ListView1.Items.Add;
   ListView1.Items[i].Caption:=data.Name;
   with ListView1.Items[i].SubItems do begin
    Add(data.Format);
    Add(data.Sprache);
   end;
  end;
end;

procedure TForm1.OpenInfo;
var
  i:Integer;
begin
  Seek(datei, ListView1.Selected.Index);
  Read(datei, data);

  Label1.Caption:=data.Name;
  Label2.Caption:=data.Format;
end;


procedure TForm1.FormCreate(Sender: TObject);
begin
  AssignFile(datei, 'index.dat');
  IF FileExists('index.dat') THEN Reset(datei)
  else Rewrite(datei);

  filllist;
end;

procedure TForm1.BitBtn1Click(Sender: TObject);
begin
  data.Name:=Edit1.Text;
  data.Format:=Edit2.Text;
  data.CDs:=Edit3.Text;
  data.Gernre:=Edit4.Text;
  data.Bild:=Edit5.Text;
  data.Ton:=Edit6.Text;
  data.Sprache:=Edit7.Text;

  seek(datei, filesize(datei)-1);
  write(datei, data);

  FillList;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  ShowMessage(IntToStr(sizeof(datei)-1));
end;

procedure TForm1.ListView1Click(Sender: TObject);
begin
  OpenInfo;
end;

end.
Hab es net so mit Records... Will aber lernen ;-)

EDIT: Die SizeOf(datei)-1 habe ich nach deinem Post erst eingebaut

alcaeus 4. Nov 2004 21:55

Re: Versuch hinter dem Dateiende zu lesen
 
:wall:

Dass mir das nicht früher aufgefallen ist: sizeof(datei) gibt dir nicht die anzahl records zurück, sondern die größe der filevariable. du musst filesize(datei)-1 verwenden.

Und weil wir schon dabei sind: beim schreiben eines neuen records musst du den zeiger auf filesize(datei) setzen, sonst überschreibst du ja den letzten record.

Greetz
alcaeus

TheMiller 4. Nov 2004 22:49

Re: Versuch hinter dem Dateiende zu lesen
 
Darf ich dich Gott nennen?!?

Mir wäre es nie aufgefallen, aber jetzt wo du es sagst.... Super! Danke :thumb:

alcaeus 4. Nov 2004 22:50

Re: Versuch hinter dem Dateiende zu lesen
 
[OT]
Zitat:

Zitat von DJ-SPM
Darf ich dich Gott nennen?!?

Ja, warum nicht? :mrgreen:
[/OT]

Greetz
alcaeus

RhodosGuard 13. Jun 2012 09:10

AW: Versuch hinter dem Dateiende zu lesen
 
Habe denselben Fehler und Blicke grad net was da falsch ist :|

Ist mein projekt für Informatik und nunja ich verzweifel da dran.

Mein Problem ist, dass das Programm entweder das Wort nicht bis ans Ende kopiert, oder ich den Datei-Fehler erhalte.
Setze ich bei der Procedure löschen Filesize(woert)-2 ein kopiert mir es das nicht auf den letzten Platz, wenn ich Filesize(woert)-1 eingebe bekomme ich 'Versuch hinter dem Dateiende zu lesen.

Delphi-Quellcode:
procedure TForm1.Button5Click(Sender: TObject);
var key:String[25];
i:integer;
h:integer;
begin
Assignfile(woert,'Wörterbuch.dat');
reset(woert);
key:=Inputbox('Abfrage','Welches Wort löschen?(bitte das englische Wort eingeben)','');
for i := 1 to filesize(woert) do begin
  read(woert,Woerterbuch);
  if key=Woerterbuch[i].Englisch then begin
    h:=i;
    löschen(h);
    exit;
  end
   else
    showmessage('Das Wort steht nicht im Wörterbuch');
  end;
closefile(woert);
end;


Procedure löschen(h:integer);
var m,Prüfung:Twoerterbuch2;
j:integer;
Warnung:String[1];
begin
assignfile(woert,'Wörterbuch.dat');
reset(woert);
for j := h to Filesize(woert)-1 do begin
  Read(woert,Woerterbuch);
  m[j]:=Woerterbuch[j];
  Woerterbuch[j]:=Woerterbuch[j+1];
  Woerterbuch[j+1]:=m[j];
  write(woert,Woerterbuch);
end;
seek(woert,(Filesize(woert))-1);
truncate(woert);
closefile(woert);
end;
Ich blick es nicht ....

Aphton 13. Jun 2012 14:09

AW: Versuch hinter dem Dateiende zu lesen
 
Ich glaube da ist selbst FileSize() in Verbindung mit der For-Schleife nicht optimal (außer wenn [in seinem Fall] data nur 1 Byte groß ist)

per EOF(Datei) kannst du gucken, ob das Ende erreicht wurde. Da man die Anzahl der Lesebefehle nicht kennt, verwendet man nicht die inidizerte Schleife (for i) sondern eine
"einfachere". Falls die Datei (IMMER) aus mindestens einem Datensatz besteht, so kann man dies mit der repeat until Schleife machen.
Ansonsten nimmt man die While Do Schleife

Beispielcodefetzen:

Delphi-Quellcode:
  AssignFile(MeineDatei, DateiName);
  {$I-}
  Reset(MeineDatei);
  {$I+}
  if IOResult <> NO_ERROR then // Datei existiert nicht, neu anlegen // NO_ERROR = 0
    ReWrite(MeineDatei);

  while not EOF(MeineDatei) do
  begin
    Read(MeineDatei, DatenSatz);
    FügeDatenSatzInZbListe(DatenSatz);
  end;
Im obrigen Beispiel ist die Position vom FilePointer auf 0 (beim Öffnen einer Datei immer 0); falls die Datei jedoch offen war und Dateioperationen durchgeführt wurden, muss dies nicht der Fall sein, deshalb eignet sich ein Seek(MeineDatei, 0) eventuell.

himitsu 13. Jun 2012 14:24

AW: Versuch hinter dem Dateiende zu lesen
 
Bei einer typisierten Datei-Variable gibt FileSize nicht die Dateigröße, sondern die Anzahl der Records an.
Delphi-Quellcode:
(RealSizeOfFile div RecSize)

Aphton 13. Jun 2012 15:05

AW: Versuch hinter dem Dateiende zu lesen
 
Achso, ok. Was bewirkt Seek() bei einer typisierten Datei? Springt er an die exakte Position, die angegeben wird, oder wird das intern mit der TypenGröße mültipliziert? Falls ja, dann würde das mit der For-Schleife auch funktionieren und der Fehler läge wo anders =/

DeddyH 13. Jun 2012 15:13

AW: Versuch hinter dem Dateiende zu lesen
 
Delphi-Referenz durchsuchenSystem.Seek
Zitat:

Mit Seek kann in Delphi eine geöffnete typisierte oder nichttypisierte Datei auf eine bestimmte Position gesetzt werden. Der Positionszeiger der Datei F wird auf die Komponente mit der Nummer N gesetzt. Die erste Komponente in einer Datei hat immer die Nummer 0.

p80286 14. Jun 2012 10:52

AW: Versuch hinter dem Dateiende zu lesen
 
Ich denke dies ist nicht ganz unproblematisch;
Delphi-Quellcode:
procedure TForm1.Button5Click(Sender: TObject);
var key:String[25];
i:integer;
h:integer;
begin
Assignfile(woert,'Wörterbuch.dat');
reset(woert);
.....
for i := 1 to filesize(woert) do begin
  read(woert,Woerterbuch);
  if key=Woerterbuch[i].Englisch then begin
    ...
    löschen(h);
    exit;
  end
   else
    ... end;
closefile(woert);
end;


Procedure löschen(h:integer);
...
begin
assignfile(woert,'Wörterbuch.dat');
reset(woert);
..
closefile(woert);
LÖSCHEN wir auf eine geöffnete Datei ausgeführt (übrigens ein Hoch auf globale Variablen).

Wenn schon global, dann aber reset und closefile auch global!

Gruß
K-H

RhodosGuard 14. Jun 2012 11:59

AW: Versuch hinter dem Dateiende zu lesen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ich weiß jetzt nicht nach wem ich mich richten soll.

Zitat:

Bei einer typisierten Datei-Variable gibt FileSize nicht die Dateigröße, sondern die Anzahl der Records an.
Also bei mir gibt Filesize im Prinzip die Anzahl der Wörter wieder die ich gespeichert habe was in meinem Fall ja auch gewollt ist

Zitat:

Falls die Datei (IMMER) aus mindestens einem Datensatz besteht, so kann man dies mit der repeat until Schleife machen.
Ansonsten nimmt man die While Do Schleife
Schon mit einer Repeat-Until schleife probiert, kein Erfolg

Zitat:

LÖSCHEN wir auf eine geöffnete Datei ausgeführt (übrigens ein Hoch auf globale Variablen).
Wenn schon global, dann aber reset und closefile auch global!
Habe das so gelernt und es ist für mich übersichtlicher wenn ich für jeden Verarbeitungsschritt meine feste Regel zum Öffnen und Schließen habe. Meinst du ich soll die Datei nicht neu öffnen und schließen? Ist das dann bei jeder "Unterprozedur" so?

Im Anhang ist dann mal meine Unit.

p80286 14. Jun 2012 12:44

AW: Versuch hinter dem Dateiende zu lesen
 
Zitat:

Zitat von RhodosGuard (Beitrag 1170824)
Habe das so gelernt und es ist für mich übersichtlicher wenn ich für jeden Verarbeitungsschritt meine feste Regel zum Öffnen und Schließen habe. Meinst du ich soll die Datei nicht neu öffnen und schließen?

Schau Dir bitte den Ablauf in den beiden Proceduren an.
Zuerst öffnest Du die Datei (assignfile+reset) dann gehst Du in einer schleife durch die Datei.
Findest Du einen zu löschenden record springst Du aus der Schleife heraus und öffnest die Datei, die immer noch offen ist erneut (assignfile+reset), das kann nicht gut gehen.
Versuch doch zumindestens folgendes:
Delphi-Quellcode:
if key=Woerterbuch[i].Englisch then begin
    ...
    closefile(woert); {------- Datei schließen!!!!!! }
    löschen(h);
    exit;
  end
Das ist zwar nicht schön, sollte aber wenigstens fehlerfrei sein.

Gruß
K-H

RhodosGuard 15. Jun 2012 08:54

AW: Versuch hinter dem Dateiende zu lesen
 
Delphi-Quellcode:
procedure TForm1.Button5Click(Sender: TObject);
var key:String[25];
i:integer;
h:integer;
begin
assignfile(woert,'Wörterbuch.dat');
Reset(woert);
key:=Inputbox('Abfrage','Welches Wort löschen?(bitte das englische Wort eingeben)','');
for i := 1 to filesize(woert) do begin
  read(woert,Woerterbuch);
  if key=Woerterbuch[i].Englisch then begin
    h:=i;
    löschen(h);
    exit;
  end;
showmessage('Das Wort steht nicht im Wörterbuch');
end;
closefile(woert);
end;

Procedure löschen(h:integer);
var m:Twoerterbuch2;
begin
Read(woert,Woerterbuch);
while h<Filesize(woert) do begin
  m[h]:=Woerterbuch[h];
  Woerterbuch[h]:=Woerterbuch[h+1];
  Woerterbuch[h+1]:=m[h];
  write(woert,Woerterbuch);
  inc(h);
end;
seek(woert,Filesize(woert)-1);
truncate(woert);
end;
SIeht mittlerweilse so aus sagt mir aber "Dateizugriff verweigert" und dannach habe ich angeblich eine Filesize von 1001 und es fehlen 2 Einträge.

p80286 15. Jun 2012 10:22

AW: Versuch hinter dem Dateiende zu lesen
 
Zitat:

Zitat von RhodosGuard (Beitrag 1171000)
SIeht mittlerweilse so aus sagt mir aber "Dateizugriff verweigert" und dannach habe ich angeblich eine Filesize von 1001 und es fehlen 2 Einträge.

und Wo sagt er das?

Delphi-Quellcode:
Procedure Loeschen(h:integer);
var
  tmpsatz : TMyWoertRec;
  maxidx : integer;
begin
  maxidx:=filesize(woert);
  repeat
    seek(woert,h+1);
    read(woert,tmpsatz);
    dec(h,1);
    seek(woert,h);
    write(woert,tmpsatz);
  until h>=maxidx;
  truncate(woert);
end;
bleibt noch das Closefile unterzubringen.

Hast Du einmal darüber nachgedacht, Deine Daten in einer TList unterzubringen?
Das wäre auf jeden Fall schneller.

Gruß
K-H


Alle Zeitangaben in WEZ +1. Es ist jetzt 18:25 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