Delphi-PRAXiS
Seite 3 von 3     123   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   FreePascal Eine lineare Liste an Strings als Datei speichern (https://www.delphipraxis.net/177561-eine-lineare-liste-strings-als-datei-speichern.html)

Sir Rufo 14. Nov 2013 18:03

AW: Eine lineare Liste an Strings als Datei speichern
 
@Popov

Das Array ist nur ein Überbleibsel (Artefakt). Die Vokabeln werden doch über die Klasse
Delphi-Quellcode:
TListe
verwaltet.

Somit muss nur noch die Listen-Instanz gespeichert bzw. geladen werden :)

Popov 14. Nov 2013 18:47

AW: Eine lineare Liste an Strings als Datei speichern
 
@Sir Rufo

Da mußt du mir weiter helfen. Vielleicht sehe ich nur nicht vor lauter Bäume den Wald nicht mehr, aber ich weiß nicht so richtig was du meinst.

In TListe gibt es einige Methoden. Guckt man sich die oberflächlich an, wie ich es anscheinend gemacht habe, entdeckt man dort die Klasse TVokabel. Auf die wird verschiedenartig zugegriffen. Ich kann mich auch täuschen, aber hier wird meiner Meinung nach die Klasse als Record genutzt. Berichtige mich wenn ich mich verguckt habe. Beispiel TListe.hinzufuegen. Mit TVokabel.initvok wird ein neueVok Objekt erstellt. Mit Erste.Naechste := neueVok wird wohl die Adresse übergeben. So langsam verliere ich da aber schon den Überblick.

thejacensolo 14. Nov 2013 19:10

AW: Eine lineare Liste an Strings als Datei speichern
 
Zitat:

Zitat von Popov (Beitrag 1235925)
@thejacensolo

Was du bisher hast ist noch nicht viel. Bisher hast du nur
Delphi-Quellcode:
speicher : array of string;
ein Array, greifst aber noch nicht drauf zu. So wie man das verstehen könne ist, dass du die Vokabeln in dem Aray speichern möchtest. Noch machst du es noch nicht, wirst es vermutlich.

Trotzdem, bisher ist noch alles offen. Nun die Frage: willst du es tatsächlich mit dem Array machen? Nichts gegen Array, dann mußt du dich aber auch um alles kümmern, also die Verwaltung, das Speichern, das Laden, usw. Das ist eine Aufgabe für sich. Nicht sehr schwer, aber etwas Programmierarbeit.

Die andere Möglichkeit ist Vorhandenes zu nutzen. Ob das nun etwas mit TStringList oder TIniFile ist, diese Klassen bieten schon eine Verwaltung an. Du mußt dich nicht mehr um das Speichern kümmern, du speicherst deine Liste einfach mit einer Zeile Code. Bei Array wird es etwas mehr Code sein.

Also für was entscheidest du dich?

Dann für die Methode mit stringlist usw.

Blup 15. Nov 2013 10:34

AW: Eine lineare Liste an Strings als Datei speichern
 
Eine seperate Klasse TStorage zum Speichern läuft letztendlich auf ein Visitor-Pattern hinaus.
Damit scheint aber der TE noch leicht überfordert zu sein.
Deshalb erst mal ein einfacher Lösungsansatz, der zwar nicht so universell aber dafür einfacher zu verstehen ist.

Wie speichert man eine Liste von Elementen in einer Datei?
Es gibt verschiedene Dateiformate die sich je nach Anwendungsfall unterschiedlich gut eignen.
Eine einfache Variante ist die CSV-Datei, dabei wird für jedes Element eine Zeile gespeichert. Jede Zeile wird mit Zeilenabschluss beendet (z.B. CRLF).
Innerhalb der Zeile sind die einzelnen Eigenschaften z.B. durch Komma getrennt.
Delphi-Quellcode:
TVokabel = class
  {...}
public
  function ObjectToCSV: string;
  procedure ObjectFromCSV(const AValue: string);
end;

TListe = class
  {...}
public
  procedure Clear;
  procedure SaveToStream(AStream: TStream);
  procedure ReadFromStream(AStream: TStream);
end;

function GetNextString(var AValue: string; const ASeperator): string;
var
  i, n: Integer;
begin
  n := Length(ASeperator);
  i := Pos(ASeperator, AValue);
  if i > 0 then
  begin
    Result := Copy(AValue, 1, i - 1);
    AValue := Copy(AValue, i + n, Length(AValue) - i - n + 1);
  end
  else
  begin
    Result := AValue;
    AValue := '';
  end;
end;

function TVokabel.ObjectToCSV: string;
begin
  Result := Deutsch + ',' + Englisch;
end;

procedure TVokabel.ObjectFromCSV(const AValue: string);
var
  s: string;
begin
  s := AValue;
  Deutsch := GetNextString(s, ',');
  Englisch := GetNextString(s, ',');
end;


procedure TListe.SaveToStream(AStream: TStream);
var
  vokabel: TVokabel;
  s: string;
begin
  vokabel := Erste;
  if Assigned(vokabel) then
  begin
    repeat
      s := vokabel.ObjectToCSV + #13#10;
      AStream.WriteBuffer(PChar(s)^, Length(s));
 
      vokabel := vokabel.naechste;
    until (vokabel = Erste);
  end;
end;

procedure TListe.ReadFromStream(AStream: TStream);
var
  sBuffer, s: string;
  vokabel: TVokabel;
begin
  Clear;
  SetLength(sBuffer, AStream.Length);
  AStream.ReadBuffer(PChar(sBuffer)^, Length(sBuffer));
  while Length(sBuffer) > 0 do
  begin
    s := GetNextString(sBuffer, #13#10);
    if Length(s) > 0 then
    begin
      vokabel := TVokabel.Create;
      vokabel.ObjectFromCSV(s);
      hinzufuegen(vokabel);
    end;
  end;
end;

stream := TFileSream.Create('MyFile.csv', fmCreate);
MyListe.SaveToStream(stream);
stream.Free;

stream := TFileSream.Create('MyFile.csv', fmRead);
MyListe.ReadFromStream(stream);
stream.Free;
Ich habe hier bewusst auf den Einsatz einer TStringList verzichtet. Wenn der TE diese Klasse und deren Möglichkeiten nicht kennt, sollte er das Probleme zuerst mit den bekannten Mitteln lösen.

Popov 15. Nov 2013 13:06

AW: Eine lineare Liste an Strings als Datei speichern
 
Die Ansätze von SirRufo und Blup finde ich zwar persönlich sehr gut und gelungen, und es ist erfreulich, dass der TE die Aufgabe mit einer Klasse löst (auch wenn es noch Probleme gibt, die Richtung stimmt zumindest), aber ich glaube zu erkennen (ich kann mich aber auch irren), dass sich der TE etwas verloren hat. Vor allem als Anfänger kann es problematisch sein am Anfang gleich zwei Hürden zu meistern. Die eine Hürde ist die Klasse. Ich finde man sollte sich erst einer Aufgabe widmen, bis die sitzt. Andere Probleme lenken davon ab, wie z. B. die Hürde beliebige Daten zu speichern. Deshalb meine Idee mit TStringList. Das kennt fast jeder, denn das ist einer der ersten Klassen die man sich genauer anguckt.

@thejacensolo

Ich hab gerade ein Beispiel geprogt. Betrachte das nicht als fertige Klasse, auch wenn sie funktioniert. Auf Sicherheitsabfrage, Fehlermeldungen usw. habe ich verzichtet, denn es ist deine Klasse. Ich hab nur ein Beispiel gemacht in dem ich verführe wie einfach diese Aufgabe mit TStringList gelöst werden kann. Den Rest mußt du alleine machten.

Delphi-Quellcode:
unit uListe;

interface

uses
  SysUtils, Classes;

type
  TVokabel2 = class
  private
    FFileName: string;
    FZeiger: Integer;
    FVokabelListe: TStringList;
    function GibZeigerVokabelDe(Zeiger: Integer): string;
  public
    constructor Create(const FileName: string);
    destructor Destroy; override;
    procedure VokabelNeu(Deutsch, Englisch: string);
    procedure VokabelBearbeiten(Deutsch, Englisch: string);
    function GibVokabelEng(VokabelDe: string): string;
    function GibVokabelDe(VokabelEng: string): string;
    function VokabelAnzahl: Integer;
    property VokabelZeiger: Integer read FZeiger;
    procedure AllesSpeichern;
    function GibErsteVokabelDe: string;
    function GibNaechsteVokabelDe: string;
    function GibVorherigeVokabelDe: string;
    function GibLetzteVokabelDe: string;
    function GibVokabelDeIndex(VokabelDe: string): Integer;
    procedure LoescheVokabel(Index: Integer);
   end;

implementation

constructor TVokabel2.Create(const FileName: string);
begin
  inherited Create;
  FFileName := FileName;
  FZeiger := 0;

  FVokabelListe := TStringList.Create;
  if FileExists(FFileName) then
    FVokabelListe.LoadFromFile(FFileName);
end;

destructor TVokabel2.Destroy;
begin
  AllesSpeichern;
  FVokabelListe.Free;
  inherited Destroy;
end;

procedure TVokabel2.VokabelNeu(Deutsch, Englisch: string);
begin
  FVokabelListe.Values[Deutsch] := Englisch;
end;

procedure TVokabel2.VokabelBearbeiten(Deutsch, Englisch: string);
begin
  VokabelNeu(Deutsch, Englisch);
end;

function TVokabel2.GibVokabelEng(VokabelDe: string): string;
begin
  Result := FVokabelListe.Values[VokabelDe];
end;

function TVokabel2.GibVokabelDe(VokabelEng: string): string;
var
  i: Integer;
begin
  Result := '';

  for i := 0 to FVokabelListe.Count - 1 do
    if SameText(VokabelEng, FVokabelListe.ValueFromIndex[i]) then
    begin
      Result := FVokabelListe.Names[i];
      Exit;
    end;
end;

function TVokabel2.VokabelAnzahl: Integer;
begin
  Result := FVokabelListe.Count;
end;

procedure TVokabel2.AllesSpeichern;
begin
  FVokabelListe.SaveToFile(FFileName);
end;

function TVokabel2.GibZeigerVokabelDe(Zeiger: Integer): string;
begin
  Result := '';

  //sind Vokablen vorhenden?
  if FVokabelListe.Count = 0 then
    Exit;

  //beim Unterschreiten der unteren Grenze, weiter mit der höhsten Vokabel
  if Zeiger < 0 then
    Zeiger := FVokabelListe.Count - 1;

  //beim Unterschreiten der oberen Grenze, weiter mit der niedrigesten Vokabel
  if Zeiger > (FVokabelListe.Count - 1) then
    Zeiger := 0;

  FZeiger := Zeiger;
  Result := FVokabelListe.Names[FZeiger];
end;

function TVokabel2.GibErsteVokabelDe: string;
begin
  Result := GibZeigerVokabelDe(0);
end;

function TVokabel2.GibNaechsteVokabelDe: string;
begin
  Result := GibZeigerVokabelDe(FZeiger + 1);
end;

function TVokabel2.GibVorherigeVokabelDe: string;
begin
  Result := GibZeigerVokabelDe(FZeiger - 1);
end;

function TVokabel2.GibLetzteVokabelDe: string;
begin
  Result := GibZeigerVokabelDe(FVokabelListe.Count - 1);
end;

function TVokabel2.GibVokabelDeIndex(VokabelDe: string): Integer;
begin
  Result := FVokabelListe.IndexOfName(VokabelDe);
end;

procedure TVokabel2.LoescheVokabel(Index: Integer);
begin
  FVokabelListe.Delete(Index);
end;

end.
Kurz zu der Beschreibung: über Create wird ein Pfad angegeben und somit eine Textdatei mit Vokalen geladen. Beim Freigeben wird automatisch gespeichert. Man kann aber auch mit AllesSpeichern selbst speichern. Über VokabelNeu wird eine Vokabel angelegt. Über Parameter gibt man das deutsche und englische Wort. Über GibVokabelEng und GibVokabelDe kann man eine Vokabel abfragen. Mit GibErsteVokabelDe, GibNaechsteVokabelDe, usw. kann man sich rauf und runter deutsche Vokabeln geben lassen. Die Englische mit der Methode oben abgefragt.


Hier noch ein Beispiel zum Testen:

Delphi-Quellcode:
uses
  uListe;

var
  VokabelListe: TVokabel2;

procedure TForm1.FormCreate(Sender: TObject);
begin
  VokabelListe := TVokabel2.Create(ChangeFileExt(ParamStr(0), '.txt'));
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  //Liste wird automatisch gesichert
  VokabelListe.Free;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  VokabelListe.VokabelNeu('Hund', 'dog');
  VokabelListe.VokabelNeu('Katze', 'cat');
  VokabelListe.VokabelNeu('Programmierer', 'programmer');
  VokabelListe.VokabelNeu('Kaffee', 'coffee');
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  ShowMessage(VokabelListe.GibErsteVokabelDe);
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  ShowMessage(VokabelListe.GibNaechsteVokabelDe);
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
  ShowMessage(VokabelListe.GibVorherigeVokabelDe);
end;

procedure TForm1.Button5Click(Sender: TObject);
begin
  ShowMessage(VokabelListe.GibLetzteVokabelDe);
end;

procedure TForm1.Button6Click(Sender: TObject);
begin
  ShowMessage(VokabelListe.GibVokabelEng('katze'));
end;

procedure TForm1.Button7Click(Sender: TObject);
begin
  ShowMessage(VokabelListe.GibVokabelDe('Coffee'));
end;

procedure TForm1.Button8Click(Sender: TObject);
begin
  ShowMessage(IntToStr(VokabelListe.VokabelZeiger));
end;

procedure TForm1.Button9Click(Sender: TObject);
begin
  ShowMessage(IntToStr(VokabelListe.VokabelAnzahl));
end;

procedure TForm1.Button10Click(Sender: TObject);
begin
  ShowMessage(IntToStr(VokabelListe.GibVokabelDeIndex('Katze')));
end;

procedure TForm1.Button11Click(Sender: TObject);
var
  k: Integer;
begin
  k := VokabelListe.GibVokabelDeIndex('Katze');
  VokabelListe.LoescheVokabel(k);
end;

thejacensolo 15. Nov 2013 15:25

AW: Eine lineare Liste an Strings als Datei speichern
 
Zitat:

Zitat von Popov (Beitrag 1236110)
Die Ansätze von SirRufo und Blup finde ich zwar persönlich sehr gut und gelungen, und es ist erfreulich, dass der TE die Aufgabe mit einer Klasse löst (auch wenn es noch Probleme gibt, die Richtung stimmt zumindest), aber ich glaube zu erkennen (ich kann mich aber auch irren), dass sich der TE etwas verloren hat. Vor allem als Anfänger kann es problematisch sein am Anfang gleich zwei Hürden zu meistern. Die eine Hürde ist die Klasse. Ich finde man sollte sich erst einer Aufgabe widmen, bis die sitzt. Andere Probleme lenken davon ab, wie z. B. die Hürde beliebige Daten zu speichern. Deshalb meine Idee mit TStringList. Das kennt fast jeder, denn das ist einer der ersten Klassen die man sich genauer anguckt.

@thejacensolo

Ich hab gerade ein Beispiel geprogt. Betrachte das nicht als fertige Klasse, auch wenn sie funktioniert. Auf Sicherheitsabfrage, Fehlermeldungen usw. habe ich verzichtet, denn es ist deine Klasse. Ich hab nur ein Beispiel gemacht in dem ich verführe wie einfach diese Aufgabe mit TStringList gelöst werden kann. Den Rest mußt du alleine machten.

Delphi-Quellcode:
unit uListe;

interface

uses
  SysUtils, Classes;

type
  TVokabel2 = class
  private
    FFileName: string;
    FZeiger: Integer;
    FVokabelListe: TStringList;
    function GibZeigerVokabelDe(Zeiger: Integer): string;
  public
    constructor Create(const FileName: string);
    destructor Destroy; override;
    procedure VokabelNeu(Deutsch, Englisch: string);
    procedure VokabelBearbeiten(Deutsch, Englisch: string);
    function GibVokabelEng(VokabelDe: string): string;
    function GibVokabelDe(VokabelEng: string): string;
    function VokabelAnzahl: Integer;
    property VokabelZeiger: Integer read FZeiger;
    procedure AllesSpeichern;
    function GibErsteVokabelDe: string;
    function GibNaechsteVokabelDe: string;
    function GibVorherigeVokabelDe: string;
    function GibLetzteVokabelDe: string;
    function GibVokabelDeIndex(VokabelDe: string): Integer;
    procedure LoescheVokabel(Index: Integer);
   end;

implementation

constructor TVokabel2.Create(const FileName: string);
begin
  inherited Create;
  FFileName := FileName;
  FZeiger := 0;

  FVokabelListe := TStringList.Create;
  if FileExists(FFileName) then
    FVokabelListe.LoadFromFile(FFileName);
end;

destructor TVokabel2.Destroy;
begin
  AllesSpeichern;
  FVokabelListe.Free;
  inherited Destroy;
end;

procedure TVokabel2.VokabelNeu(Deutsch, Englisch: string);
begin
  FVokabelListe.Values[Deutsch] := Englisch;
end;

procedure TVokabel2.VokabelBearbeiten(Deutsch, Englisch: string);
begin
  VokabelNeu(Deutsch, Englisch);
end;

function TVokabel2.GibVokabelEng(VokabelDe: string): string;
begin
  Result := FVokabelListe.Values[VokabelDe];
end;

function TVokabel2.GibVokabelDe(VokabelEng: string): string;
var
  i: Integer;
begin
  Result := '';

  for i := 0 to FVokabelListe.Count - 1 do
    if SameText(VokabelEng, FVokabelListe.ValueFromIndex[i]) then
    begin
      Result := FVokabelListe.Names[i];
      Exit;
    end;
end;

function TVokabel2.VokabelAnzahl: Integer;
begin
  Result := FVokabelListe.Count;
end;

procedure TVokabel2.AllesSpeichern;
begin
  FVokabelListe.SaveToFile(FFileName);
end;

function TVokabel2.GibZeigerVokabelDe(Zeiger: Integer): string;
begin
  Result := '';

  //sind Vokablen vorhenden?
  if FVokabelListe.Count = 0 then
    Exit;

  //beim Unterschreiten der unteren Grenze, weiter mit der höhsten Vokabel
  if Zeiger < 0 then
    Zeiger := FVokabelListe.Count - 1;

  //beim Unterschreiten der oberen Grenze, weiter mit der niedrigesten Vokabel
  if Zeiger > (FVokabelListe.Count - 1) then
    Zeiger := 0;

  FZeiger := Zeiger;
  Result := FVokabelListe.Names[FZeiger];
end;

function TVokabel2.GibErsteVokabelDe: string;
begin
  Result := GibZeigerVokabelDe(0);
end;

function TVokabel2.GibNaechsteVokabelDe: string;
begin
  Result := GibZeigerVokabelDe(FZeiger + 1);
end;

function TVokabel2.GibVorherigeVokabelDe: string;
begin
  Result := GibZeigerVokabelDe(FZeiger - 1);
end;

function TVokabel2.GibLetzteVokabelDe: string;
begin
  Result := GibZeigerVokabelDe(FVokabelListe.Count - 1);
end;

function TVokabel2.GibVokabelDeIndex(VokabelDe: string): Integer;
begin
  Result := FVokabelListe.IndexOfName(VokabelDe);
end;

procedure TVokabel2.LoescheVokabel(Index: Integer);
begin
  FVokabelListe.Delete(Index);
end;

end.
Kurz zu der Beschreibung: über Create wird ein Pfad angegeben und somit eine Textdatei mit Vokalen geladen. Beim Freigeben wird automatisch gespeichert. Man kann aber auch mit AllesSpeichern selbst speichern. Über VokabelNeu wird eine Vokabel angelegt. Über Parameter gibt man das deutsche und englische Wort. Über GibVokabelEng und GibVokabelDe kann man eine Vokabel abfragen. Mit GibErsteVokabelDe, GibNaechsteVokabelDe, usw. kann man sich rauf und runter deutsche Vokabeln geben lassen. Die Englische mit der Methode oben abgefragt.


Hier noch ein Beispiel zum Testen:

Delphi-Quellcode:
uses
  uListe;

var
  VokabelListe: TVokabel2;

procedure TForm1.FormCreate(Sender: TObject);
begin
  VokabelListe := TVokabel2.Create(ChangeFileExt(ParamStr(0), '.txt'));
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  //Liste wird automatisch gesichert
  VokabelListe.Free;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  VokabelListe.VokabelNeu('Hund', 'dog');
  VokabelListe.VokabelNeu('Katze', 'cat');
  VokabelListe.VokabelNeu('Programmierer', 'programmer');
  VokabelListe.VokabelNeu('Kaffee', 'coffee');
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  ShowMessage(VokabelListe.GibErsteVokabelDe);
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  ShowMessage(VokabelListe.GibNaechsteVokabelDe);
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
  ShowMessage(VokabelListe.GibVorherigeVokabelDe);
end;

procedure TForm1.Button5Click(Sender: TObject);
begin
  ShowMessage(VokabelListe.GibLetzteVokabelDe);
end;

procedure TForm1.Button6Click(Sender: TObject);
begin
  ShowMessage(VokabelListe.GibVokabelEng('katze'));
end;

procedure TForm1.Button7Click(Sender: TObject);
begin
  ShowMessage(VokabelListe.GibVokabelDe('Coffee'));
end;

procedure TForm1.Button8Click(Sender: TObject);
begin
  ShowMessage(IntToStr(VokabelListe.VokabelZeiger));
end;

procedure TForm1.Button9Click(Sender: TObject);
begin
  ShowMessage(IntToStr(VokabelListe.VokabelAnzahl));
end;

procedure TForm1.Button10Click(Sender: TObject);
begin
  ShowMessage(IntToStr(VokabelListe.GibVokabelDeIndex('Katze')));
end;

procedure TForm1.Button11Click(Sender: TObject);
var
  k: Integer;
begin
  k := VokabelListe.GibVokabelDeIndex('Katze');
  VokabelListe.LoescheVokabel(k);
end;

Danke das hat mir sehr geholfen ;-) ich weiß aber gar nicht, was valuefromindex bedeutet, oder wer oder was index ist. eine Tvokabel? eine liste? eine Methode?

p80286 15. Nov 2013 15:39

AW: Eine lineare Liste an Strings als Datei speichern
 
Dann schau mal in die OH zu TStrings.
ValueFromIndex gibt von
Zitat:

Hund=dog
dog zurück und index ist die "Zeilennumber" der Listeneinträge.
Der kleinste Index ist 0 der größte
Delphi-Quellcode:
Liste.count-1
Gruß
K-H


Alle Zeitangaben in WEZ +1. Es ist jetzt 01:56 Uhr.
Seite 3 von 3     123   

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