Letzter Datensatz wird nicht eingelesen.

Für Themen zu Datenbanken und Zugriff auf diese. Auch für Datenbankkomponenten.
Antworten
barahir1983
Beiträge: 9
Registriert: Do 14. Dez 2006, 09:34
Kontaktdaten:

Letzter Datensatz wird nicht eingelesen.

Beitrag von barahir1983 »

Hallo an alle!

Ich habe ein Projekt, das aus einer CSV-Datei der Herrnhuter Losungen pro Tag eine LaTeX-Datei erstellt. Dafür habe ich ein TSdfDataSet (namens "Datei", s.u.) und eine TDatasource verwendet. Jetzt habe ich ein Problem, dessen Ursprung ich nicht ganz verstehe: Wenn ich die Losungen einlesen lasse, verschwindet der 31.12., also der letzte Datensatz. Folgender Code schreibt in die Dateien:

Code: Alles auswählen

 
with Datei do begin
  Open;
  DisableControls;
  for i:=2 to RecordCount do begin
    ProgressBar1.Position:=i;
    RecNo:=i;
    StaticText1.Caption:=InttoStr(i)+' von '+InttoStr(RecordCount);
    Memo1.Lines.Add('{\large\textbf{Losung f\"ur '+Fields[1].AsString+', '+Fields[0].AsString+'}}\par ');
    Memo1.Lines.Add('\textsc{'+Fields[2].AsString+'}\par ');
    Memo1.Lines.Add('\textit{Losungstext: '+Fields[3].AsString+'}\par ');
    Memo1.Lines.Add(Fields[4].AsString+'\par ');
    Memo1.Lines.Add('\textit{Lehrtext: '+Fields[5].AsString+'}\par ');
    Memo1.Lines.Add(Fields[6].AsString+'\par');
    Memo1.Lines.SaveToFile(Edit1.Text+Fields[0].AsString+'.tex');
    Memo1.Clear;
  end;
  StaticText1.Caption:='Fertig.';
  EnableControls;
  if MessageDlg('Fertig!','Aktion abgeschlossen. Soll das Programm jetzt beendet werden?',mtConfirmation,[mbYes,mbNo],0) = mrYes then MainBox.Close;
end;
 
i=2 wurde notwendig, da sonst die Steuerzeile auch in eine Datei umgewandelt wurde.

Wer weiß was ich falsch gemacht habe? Ich bin über jeden Hinweis dankbar...
Falls jemand noch mehr Code benötigt, habe ich das Projekt angehängt. Die Losungen sind hier verfügbar: http://www.brueder-unitaet.de/download/ ... 08_CSV.zip" onclick="window.open(this.href);return false;

Danke schon mal im Voraus,

David
Dateianhänge
los2latex.zip
Das Corpus Delicti. Ein Testlauf mit Dateien befindet sich ebenfalls im Archiv.
(144.93 KiB) 78-mal heruntergeladen

khh
Beiträge: 489
Registriert: Sa 5. Apr 2008, 09:37
OS, Lazarus, FPC: Win Vista,Win 7 (L 0.9.29 FPC 2.4.1)
CPU-Target: 32Bit /64 Bit
Wohnort: Nähe Freiburg i.Br.

Re: Letzter Datensatz wird nicht eingelesen.

Beitrag von khh »

wie kommst du darauf i auf 2 zu setzen?

normalerweise zählt man von 0 ab ;-)

setze mal eine zählvariable ans ende der schleife und prüfe wie oft die schleife durchlaufen wird.

Gruss Kh

Socke
Lazarusforum e. V.
Beiträge: 3177
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Letzter Datensatz wird nicht eingelesen.

Beitrag von Socke »

khh hat geschrieben:wie kommst du darauf i auf 2 zu setzen?

normalerweise zählt man von 0 ab ;-)

setze mal eine zählvariable ans ende der schleife und prüfe wie oft die schleife durchlaufen wird.

Gruss Kh
Ich schätze mal, dass 2 die Zweite Zeile heißen soll; in CSV-Dateien beinhaltet die erste Zeile die Spaltennamen, also keinen Datensatz. Da man aber eigentlich von 0 anfängt zu zählen (wie du bereits sagtest), wäre die zweite Zeile dann die Nummer 1. Wobei ich nicht weiß, wie TSdfDataSet das handhabt.

Eine Alternative bestände in der Verwendung von TStrings; damit hab ich das mal gemacht.

Code: Alles auswählen

uses Classes, SysUtils;
function ProcessFile( const AFileName: TFileName ) ;
var s1, s2: TStrings;
      i, z: Integer;
begin
  { Stringlisten erstellen }
  s1 := TStringList.Create;
  s2 := TStringList.Create;
  try
    { Textdatei laden }
    s1.LoadFromFile( AFileName ) ;
    { Trennzeichen zwischen den einzelnen Werten setzten }
    s2.Delimiter := ';';
    { Zeichen setzten, in dem die Werte eingefasst werden, wenn sie bspw. das Trennzeichen enthalten }
    s2.QuoteChar := '"';
    { Schleife durchlaufen; i := 1, da erste Zeile (0) die Spaltennamen enthält.
      Wenn auch die Spaltennamen (i := 0) ausgegeben werden, empfiehlt es sich, dies außerhalb der Schleife zu machen, da dann nicht jedesmal eine if-Abfrage durchgeführt werden muss. }
    for i := 1 to s1.Count-1 do begin
      WriteLn('Zeile: ', i);
      s2.DelimetedText := s1.Strings[i];
      for z := 0 to s2.Count-1 do
        WriteLn('  ',z, '.Spalte: ',s2[z]);
    end;
  finally
    { Stringlisten freigeben }
    s1.Free;
    s2.Free;
  end;
end;
 
 
Solange du die CSV-Datei nicht als Datenbanktabelle verwenden willst, sondern nur ein paar Daten entnehmen, ist das hier der einfachste weg, musst du nur noch anpassen.
Mfg Socke

P.S: Mit Syntaxfehlern kann man die Code-Herforhebung auch außerhalb der code-Tags gebrauchen...
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

barahir1983
Beiträge: 9
Registriert: Do 14. Dez 2006, 09:34
Kontaktdaten:

Re: Letzter Datensatz wird nicht eingelesen.

Beitrag von barahir1983 »

Vielen Dank für die Hilfe!
Ich habe das Beispiel von Socke gerade versucht zu implementieren, bin aber nicht ganz im Klaren darüber, warum mir immer wieder folgendes gesagt wird:

Code: Alles auswählen

l2lmain.pas(37,14) Error: Forward declaration not solved "TMainBox.ProcessFile(const AnsiString):Boolean" 
Meine Deklaration sieht so aus:

Code: Alles auswählen

public
    function ProcessFile(const AFileName: TFileName): boolean;
Die Funktion habe ich folgendermaßen angepasst:

Code: Alles auswählen

function ProcessFile(const AFileName: TFileName): boolean;
var s1, s2: TStrings;
    before: string;
      i, j: Integer;
begin
  { Stringlisten erstellen }
  s1 := TStringList.Create;
  s2 := TStringList.Create;
  try
    { Textdatei laden }
    s1.LoadFromFile( AFileName ) ;
    { Trennzeichen zwischen den einzelnen Werten setzten }
    s2.Delimiter := ';';
    { Zeichen setzten, in dem die Werte eingefasst werden, wenn sie bspw. das Trennzeichen enthalten }
    s2.QuoteChar := '"';
    { Schleife durchlaufen; i := 1, da erste Zeile (0) die Spaltennamen enthält.
      Wenn auch die Spaltennamen (i := 0) ausgegeben werden, empfiehlt es sich, dies außerhalb der Schleife zu machen, da dann nicht jedesmal eine if-Abfrage durchgeführt werden muss. }
    for i := 1 to s1.Count-1 do begin
    Tageslosung[i].No:=i;
    Count:=i;
    MainBox.ProgressBar1.Position:=i;
    MainBox.StaticText1.Caption:=InttoStr(i);
    s2.DelimitedText :=StringReplace(s1.Strings[i],'.20','.',[rfReplaceAll,rfIgnoreCase]);
    for j := 0 to s2.Count-1 do
      before:=StringReplace(s2[j],'#','--',[rfReplaceAll,rfIgnoreCase]);
      Tageslosung[i].Feld[j]:=StringReplace(before,'/',' ',[rfReplaceAll,rfIgnoreCase]);
    end;
  finally
    { Stringlisten freigeben }
    s1.Free;
    s2.Free;
  end;
  result:=true;
end;
Und so wird sie aufgerufen:

Code: Alles auswählen

procedure TMainBox.MenuItem1Click(Sender: TObject);
begin
  with OpenDialog do begin
  Execute;
  if not ProcessFile(FileName) then ShowMessage('Ein Fehler ist aufgetreten');
  end;
  // Konvertierung aktivieren.
  MainBox.Caption:='Losung2LaTeX '+OpenDialog.Filename+' geladen. Bitte "Start" anclicken.';
  MenuItem2.Enabled:=true;
  StaticText1.Caption:='';
end;
So wie ich das sehe, muss es an der Deklaration liegen. Hab ich die an falscher Stelle eingefügt, habe ich irgendetwas übersehen?

Nochmals danke!
Zuletzt geändert von barahir1983 am Mi 15. Okt 2008, 10:55, insgesamt 2-mal geändert.

Benutzeravatar
theo
Beiträge: 10865
Registriert: Mo 11. Sep 2006, 19:01

Re: Letzter Datensatz wird nicht eingelesen.

Beitrag von theo »

barahir1983 hat geschrieben:Error: Forward declaration not solved "TMainBox.ProcessFile(const AnsiString):Boolean"
Du musst nur die Meldung richtig lesen.
TMainBox.....
Deine Processfile ist aber keine Methode von TMainBox sondern eine normale Funktion.
Entweder du schreibst in der Implementation TMainBox.ProcessFile(... oder du nimmst die (forward) Deklaration aus TMainBox raus.

barahir1983
Beiträge: 9
Registriert: Do 14. Dez 2006, 09:34
Kontaktdaten:

Re: Letzter Datensatz wird nicht eingelesen.

Beitrag von barahir1983 »

AAAH. Danke!
Ich krieg noch mal die Krise mit dem Programm...

barahir1983
Beiträge: 9
Registriert: Do 14. Dez 2006, 09:34
Kontaktdaten:

Re: Letzter Datensatz wird nicht eingelesen.

Beitrag von barahir1983 »

und es geht weiter...

jetzt bekomme ich nämlich einen "Range Check Error". Was steckt nu wieder dahinter??

Die Variablen (Beispiel oben) sind folgendermaßen definiert:

Code: Alles auswählen

type
 Datensatz = array[0..368] of record
      No: integer;
      Feld: array[0..7] of string;
      end;
var
  MainBox: TMainBox;
  Tageslosung: Datensatz;
  Count: integer;

Socke
Lazarusforum e. V.
Beiträge: 3177
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Letzter Datensatz wird nicht eingelesen.

Beitrag von Socke »

barahir1983 hat geschrieben:

Code: Alles auswählen

type
 Datensatz = array[0..368] of record
      No: integer;
      Feld: array[0..7] of string;
      end;
Ich bin ja immer dafür, für solche Sachen die Typen schön einzeln zu deklarieren:

Code: Alles auswählen

type
  TStrArray = array[0..7] of String;
  TMyRecord = record
    No: Integer;
   Feld: TStrArray;
  end;
  TDatensatz = array [0..368] of TMyRecord;
Dann kannst du bspw MyRecord := Datensatz[1]; machen und damit arbeiten (wenn du das brauchst);
Zu den "Range Check Error": Deine Deklaration wird bei mir problemlos kompiliert. Wie greifst du denn auf die Variablen zu?
Bei arrays mit zugriff durch schleifen kann man das so anstellen:

Code: Alles auswählen

procedure DoSth(const dat: TDatensatz);
var i: Integer;
     rec: TMyRecord;
begin
  for i := low(dat) to high(dat) do begin { low = 0; high = 386; length = 387 }
    {jetzt irgendetwas tun}
    rec := dat[i];
    WriteLn(rec.Feld[1]); {auch hier wieder aufpassen! low = 0; high = 7; length = 8}
  end;
end;
Du kannst mi low() auf das erste und mit high() auf das letzte Element eines Arrays zugreifen (bei length ist das letzte Element length()-1).

MfG Socke
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

barahir1983
Beiträge: 9
Registriert: Do 14. Dez 2006, 09:34
Kontaktdaten:

Re: Letzter Datensatz wird nicht eingelesen.

Beitrag von barahir1983 »

Es geht in diesem Fall nicht um den Compiler, der meckert, sondern um die Ausführung. Beim ersten Datensatz bleibt er bereits hängen mit der Fehlermeldung: Range Check Error. Die Ausleseprozedur läuft so ab:

Code: Alles auswählen

function TMainBox.ProcessFile(const AFileName: TFileName): boolean;
var s1, s2: TStrings;
    before: string;
    i, j: Integer;
begin
  { Stringlisten erstellen }
  s1 := TStringList.Create;
  s2 := TStringList.Create;
  try
    { Textdatei laden }
    s1.LoadFromFile( AFileName ) ;
    { Trennzeichen zwischen den einzelnen Werten setzen }
    s2.Delimiter := ';';
    { Zeichen setzen, in dem die Werte eingefasst werden, wenn sie bspw. das Trennzeichen enthalten }
    s2.QuoteChar := '"';
    { Schleife durchlaufen; i := 1, da erste Zeile (0) die Spaltennamen enthält.
      Wenn auch die Spaltennamen (i := 0) ausgegeben werden, empfiehlt es sich, dies außerhalb der Schleife zu machen, da dann nicht jedesmal eine if-Abfrage durchgeführt werden muss. }
    for i := 1 to s1.Count-1 do begin
    Tageslosung[i].No:=i;
    Count:=i;
    ProgressBar1.Position:=i;
    StaticText1.Caption:=InttoStr(i);
    s2.DelimitedText :=StringReplace(s1.Strings[i],'.20','.',[rfReplaceAll,rfIgnoreCase]);
    for j := 0 to s2.Count-1 do
      before:=StringReplace(before,'/',' ',[rfReplaceAll,rfIgnoreCase]);
      Tageslosung[i].Feld[j]:=before;
    end;
  finally
    { Stringlisten freigeben }
    s1.Free;
    s2.Free;
  end;
  result:=true;
end;
Die Deklaration des Record läuft jetzt nach deinen Vorschlägen so ab:

Code: Alles auswählen

type
 StringRec = array[0..7] of string;
 Datensatz = record
      No: integer;
      Feld: StringRec;
      end;
var
  Tageslosung: array[0..368] of Datensatz;
Hilft alles nix bisher, irgendwas muss bei der Einleseroutine schieflaufen. Was, weiß ich leider nicht. Irgendwelche Ideen? Ich stehe vollkommen auf der Leitung.

EDIT: habe mal zum Testen die Datei, die ich auslese, mitgeliefert (im Dateianhang)
Dateianhänge
Losung_2008_CSV.zip
CSV-Datei aus dem ZIP ist die auszulesende Datei
(39.95 KiB) 81-mal heruntergeladen

Benutzeravatar
theo
Beiträge: 10865
Registriert: Mo 11. Sep 2006, 19:01

Re: Letzter Datensatz wird nicht eingelesen.

Beitrag von theo »

Naja, ich finde zwar öffentliches Debugging nicht so toll, aber willst du dir den Code nicht nochmal genauer ansehen?
Bekommt deine Variable "before" irgendwo einen Wert zugewiesen?
Sollte nach for "j := 0 to s2.Count-1 do" nicht ein "begin..end" kommen?
Du solltest das einfach mal konzentriert analysieren. Sowas gehört imho nicht ins Forum.

barahir1983
Beiträge: 9
Registriert: Do 14. Dez 2006, 09:34
Kontaktdaten:

Re: Letzter Datensatz wird nicht eingelesen.

Beitrag von barahir1983 »

Das ist jetzt wieder so eine Antwort, über die ich mich so richtig freue... :roll:
Das begin... end stimmt, das mit before auch: ich hatte eine Zeile, in der es definiert wurde, herausgenommen.
Dennoch finde ich Kommentare wie "das gehört nicht in das Forum" eher wenig hilfreich. Die gehören nämlich meines Erachtens nicht ins Forum....

Wie dem auch sei, der Fehler verschwand jetzt.

Die Lösung war in dem DelimitedText versteckt. Dieser hat nämlich nicht nur an ";" getrennt sondern auch an " " (also Leerzeichen) und hatte somit mehr als sieben Einträge.

Diese Routine hilft jetzt darüber hinweg, leider nicht ganz ohne "dirty tricks":

Code: Alles auswählen

function TMainBox.ProcessFile(const AFileName: TFileName): boolean;
var s1, s2: TStrings;
    before: string;
    i, j: Integer;
begin
  { Stringlisten erstellen }
  s1 := TStringList.Create;
  s2 := TStringList.Create;
  try
    { Textdatei laden }
    s1.LoadFromFile( AFileName ) ;
    { Trennzeichen zwischen den einzelnen Werten setzen }
    s2.Delimiter := ';';
    { Zeichen setzen, in dem die Werte eingefasst werden, wenn sie bspw. das Trennzeichen enthalten }
    // s2.QuoteChar := '"';
    { Schleife durchlaufen; i := 1, da erste Zeile (0) die Spaltennamen enthält.
      Wenn auch die Spaltennamen (i := 0) ausgegeben werden, empfiehlt es sich, dies außerhalb der Schleife zu machen, da dann nicht jedesmal eine if-Abfrage durchgeführt werden muss. }
    for i := 1 to s1.Count-1 do begin
    Tageslosung[i].No:=i;
    Count:=i;
    ProgressBar1.Position:=i;
    StaticText1.Caption:=InttoStr(i);
    before:=StringReplace(s1.Strings[i],' ','€',[rfReplaceAll,rfIgnoreCase]); // Leerzeichen ersetzen, damit sie nicht als Delimiter verwendet werden können
    s2.DelimitedText :=StringReplace(before,'.20','.',[rfReplaceAll,rfIgnoreCase]); // Datumsformat kurz.
    s2.Text:=StringReplace(s2.Text,'€',' ',[rfReplaceAll,rfIgnoreCase]); // Leerzeichen wieder hinein
    for j := 0 to s2.Count-1 do begin
      before:=StringReplace(s2[j],'#','',[rfReplaceAll,rfIgnoreCase]);
      Tageslosung[i].Feld[j]:=StringReplace(before,'/','',[rfReplaceAll,rfIgnoreCase]);
      end;
    end;
  finally
    { Stringlisten freigeben }
    s1.Free;
    s2.Free;
  end;
  result:=true;
end;
Danke für alle Hinweise!

Benutzeravatar
theo
Beiträge: 10865
Registriert: Mo 11. Sep 2006, 19:01

Re: Letzter Datensatz wird nicht eingelesen.

Beitrag von theo »

barahir1983 hat geschrieben:Das ist jetzt wieder so eine Antwort, über die ich mich so richtig freue... :roll:
..
Dennoch finde ich Kommentare wie "das gehört nicht in das Forum" eher wenig hilfreich. Die gehören nämlich meines Erachtens nicht ins Forum....
Immerhin habe ich mir deinen Code mal angeschaut und dir ein paar Tipps gegeben,.
Ich helfe gerne, aber einfach sowas hingeschludertes ins Forum legen und die anderen arbeiten lassen finde ich unanständig.
Es geht ja hier nicht um etwas was du nicht weisst, sondern nur um sorgfältiges Arbeiten.

Christian
Beiträge: 6079
Registriert: Do 21. Sep 2006, 07:51
OS, Lazarus, FPC: iWinux (L 1.x.xy FPC 2.y.z)
CPU-Target: AVR,ARM,x86(-64)
Wohnort: Dessau
Kontaktdaten:

Re: Letzter Datensatz wird nicht eingelesen.

Beitrag von Christian »

Full Ack @Theo
W.m.k.A.h.e.m.F.h. -> http://www.gidf.de/

barahir1983
Beiträge: 9
Registriert: Do 14. Dez 2006, 09:34
Kontaktdaten:

Re: Letzter Datensatz wird nicht eingelesen.

Beitrag von barahir1983 »

Trotz allem denke ich das Thema kann als gelöst markiert werden. Bin leider noch Anfänger und daher nicht ganz so fit wie manch anderer hier, drum hab ich ja auch um Hilfe gebeten... Nur mal noch zur Erklärung: das hier im Forum abgelegte war auch eine Zwischenversion; leider hatte ich da das mit der Variable übersehen. Sorry wenns so stört.

Antworten