Autor Beitrag
Mashalla
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 48

Windows 7 Professional
Delphi 7 Enterprise, Turbo Delphi Explorer 2006
BeitragVerfasst: Di 02.02.10 20:56 
Ich will mittels TFileStream Informationen in eine Datei schreiben und diese dann speichern. Habe bisher kaum mit TFileStream gearbeitet, mit den Write und Read Methoden noch gar nicht. Problem ist jetzt, dass die gespeicherte Datei eine Größe von 0 Byte hat und ich weiß ned, woran es liegt. TCatalogue ist eine von ObjectList abgeleitete Klasse, TVoc is auch was eigenes. Die erste ShowMessage funktioniert, die 2. dagegen bleibt leer. Compiler meckert nicht, fehlende Zugriffsrechte oder sowas sinds auch nicht. Kann mir jemand dabei helfen?

PS: Warum erkennt mein Compiler eigentlich die Mode-Parameter "fmShareExclusive" und so nicht? Habe Classes und Contnrs eingebunden ...
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
  //////////////////////////////////////////////////////////////////////////////
  // Speichert einen Katalog in einer Datei
  //////////////////////////////////////////////////////////////////////////////
  procedure TCatalogue.SaveToFile(FName: string);
  var
    Stream: TFileStream;
    I: Integer;
    Voc: TVoc;
  begin
    try
      try
        Stream := TFileStream.Create(FName, fmCreate);
        for I := 0 to self.Items - 1 do
        begin
          // aktuelles Objekt aus der Liste holen und in den Stream schreiben
          Voc := (self.Items[I]) as TVoc;
          Stream.WriteBuffer(Voc.Source, SizeOf(Voc.Source));
          Stream.WriteBuffer(Voc.Dest, SizeOf(Voc.Dest));
          Stream.WriteBuffer(Voc.Desc, SizeOf(Voc.Desc));
        end;
      except
        // Fehler abfangen
      end;
    finally
      Stream.Free;
    end;
  end;

  //////////////////////////////////////////////////////////////////////////////
  // Lädt einen Katalog aus einer Datei
  //////////////////////////////////////////////////////////////////////////////
  procedure TCatalogue.LoadFromFile(FName: string);
  var
    Stream: TFileStream;
    Voc: TVoc;
    Source, Dest, Desc: string;
  begin
    try
      try
        Stream := TFileStream.Create(FName, fmCreate);
        Stream.Position := 0;
        Stream.Read(Source, SizeOf(Source));
        Stream.Read(Dest, SizeOf(Dest));
        Stream.Read(Desc, SizeOf(Desc));
        Voc := TVoc.Create(Source, Dest, Desc);
        self.Add(Voc);
      except
        // Fehler abfangen
      end;
    finally
      Stream.Free;
    end;
  end;

// Aufruf
procedure TMainForm.FormCreate(Sender: TObject);
var
  MyArray: array[0..2of string;
  MyCat, MyCat2: TCatalogue;
  MyVoc, MyVoc2: TVoc;

begin
  ... 

  MyVoc := TVoc.Create('a','b');
  MyCat := TCatalogue.Create(MyVoc);
  MyCat2 := TCatalogue.Create;
  ShowMessage(MyVoc.Source);
  MyCat.SaveToFile('Test.abc');
  MyCat2.LoadFromFile('Test.abc');
  ShowMessage(IntToStr(SizeOf(MyCat2)));
  MyVoc2 := (MyCat2.First) as TVoc;
  ShowMessage(MyVoc2.Source);
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Di 02.02.10 21:14 
Moin!

user profile iconMashalla hat folgendes geschrieben Zum zitierten Posting springen:
TCatalogue ist eine von ObjectList abgeleitete Klasse, TVoc is auch was eigenes.
Zeig mal die Deklarationen der Objekte, das ist nicht ganz unwesentlich bei solchen Problemen. :nixweiss:

user profile iconMashalla hat folgendes geschrieben Zum zitierten Posting springen:
PS: Warum erkennt mein Compiler eigentlich die Mode-Parameter "fmShareExclusive" und so nicht? Habe Classes und Contnrs eingebunden ...
Die Konstanten werden in SysUtils deklariert (D7).

Das hier geht allerdings ganz sicher nicht:
user profile iconMashalla hat folgendes geschrieben Zum zitierten Posting springen:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
  procedure TCatalogue.LoadFromFile(FName: string);
  var
    Stream: TFileStream;
    Voc: TVoc;
    Source, Dest, Desc: string// im Hinblick auf D2k9+ solltest du das präzisieren, das gibt Chaos...
  begin
    try
      try
        Stream := TFileStream.Create(FName, fmCreate);
        Stream.Position := 0;
        Stream.Read(Source, SizeOf(Source)); // Die Adresse stimmt nicht und die Datenmenge auch nicht,
        Stream.Read(Dest, SizeOf(Dest)); // hast du ja nirgendwo festgelegt
        Stream.Read(Desc, SizeOf(Desc));
        Voc := TVoc.Create(Source, Dest, Desc);
Wie gesagt, zeig mal die Deklarationen deiner Objekte, dann sehen wir weiter. :idea:

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
Mashalla Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 48

Windows 7 Professional
Delphi 7 Enterprise, Turbo Delphi Explorer 2006
BeitragVerfasst: Di 02.02.10 22:06 
TCatalogue

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
  type TCatalogue = class(TObjectList)

  private

  public

    ////////////////////////////////////////////////////////////////////////////
    // Erzeugt die Objektliste und fügt den Vokabelparameter der neuen Liste
    // hinzu
    // @Param:
    //   Eine Vokabel vom Typ TVoc
    ////////////////////////////////////////////////////////////////////////////
    constructor Create(FVoc: TVoc); overload;

    constructor Create; overload;

    ////////////////////////////////////////////////////////////////////////////
    // Speichert die Objektliste in einer Datei
    // @Param:
    //   Der volle Dateipfad zur Speicherung
    ////////////////////////////////////////////////////////////////////////////
    procedure SaveToFile(FName: string);

    ////////////////////////////////////////////////////////////////////////////
    // Lädt die Objektliste aus einer Datei
    // @Param:
    //   Der volle Dateipfad zum Laden
    ////////////////////////////////////////////////////////////////////////////
    procedure LoadFromFile(FName: string);

  end;


TVoc

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
type TVoc = class

  private

    FSource: String// Die Vokabel
    FDest: String;   // Die Übersetzung der Vokabel
    FDesc: String;   // Eine optionale Beschreibung, welche nicht abgefragt wird

    ////////////////////////////////////////////////////////////////////////////
    // Setzt einen neuen Quellnamen des Objektes
    ////////////////////////////////////////////////////////////////////////////
    procedure setVocSource(newSource: string);

    ////////////////////////////////////////////////////////////////////////////
    // Setzt einen neuen Zielnamen des Objektes
    ////////////////////////////////////////////////////////////////////////////
    procedure setVocDest(newDest: string);

    ////////////////////////////////////////////////////////////////////////////
    // Setzt einen neuen Beschreibung des Objektes
    ////////////////////////////////////////////////////////////////////////////
    procedure setVocDesc(newDesc: string);

  public

    ////////////////////////////////////////////////////////////////////////////
    // Erzeugt eine neue Instanz der Vokabelklasse und initialisiert die Vokabel
    ////////////////////////////////////////////////////////////////////////////
    constructor Create(Source: string; Dest: string; Desc: string); overload;
    constructor Create(Source: string; Dest: string); overload;

    ////////////////////////////////////////////////////////////////////////////
    // Eigenschaften zum Lesen und Schreiben von Werten der Variablen
    ////////////////////////////////////////////////////////////////////////////
    property Source: string read FSource write setVocSource;
    property Dest: string read FDest write setVocDest;
    property Desc: string read FDesc write setVocDesc;

  end;


Ist das das gewünschte? Schreibe später noch 2-3 Dinge dazu ;)

Nachtrag:
Ich will die Objekte einer ObjectList speichern. Da es hierfür nix einfaches fertiges gibt, dachte ich, ich schreibe einfach die einzelnen Objektattribute in einen Stream und erstelle beim Laden die Objekte neu und lade sie in die Containerliste. Soweit zum Plan ;)

Also 2k9+ interessiert mich aktuell nicht wirklich, hab mich bezüglich Unicode usw auch noch nicht schlau gemacht ;)

Wie gesagt, hab nicht genau ne Peilung, wie FileStream funktioniert. Was bringt mir der Buffer? Wird dorthinein gespeichert, was gelesen wird bzw dort heraus geschrieben? Finde zwar genügend Beispiele, aber klar wirds mir dadurch auch nicht. Und vor allem, dass der Buffer typenlos ist, macht mich stutzig, kenne sowas bisher nicht...
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Di 02.02.10 23:44 
Moin!

Hier mal ein Vorschlag, wie ich das umgesetzt hätte: ;)
ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
137:
138:
139:
140:
141:
142:
143:
144:
145:
146:
147:
148:
149:
150:
151:
152:
153:
154:
155:
156:
157:
158:
159:
160:
161:
162:
163:
164:
165:
166:
167:
168:
169:
170:
171:
172:
173:
174:
175:
176:
177:
178:
179:
180:
181:
182:
183:
184:
185:
186:
187:
188:
189:
190:
191:
uses
  ..., Contnrs;

type
  TVoc = class(TObject)
  private
    FSource: AnsiString;
    FDest: AnsiString;
    FDesc: AnsiString;   
  public
    constructor Create(const ASource, ADest: AnsiString; const ADesc: AnsiString = '');
    constructor CreateFromStream(AStream: TStream);
    property Source: AnsiString read FSource write FSource;
    property Dest: AnsiString read FDest write FDest;
    property Desc: AnsiString read FDesc write FDesc;
    procedure WriteToStream(AStream: TStream);
    procedure ReadFromStream(AStream: TStream);
    function Dump: AnsiString;
  end;

  TCatalogue = class(TObjectList)
  public
    procedure SaveToStream(AStream: TStream);
    procedure LoadFromStream(AStream: TStream);
    procedure SaveToFile(const FName: String);
    procedure LoadFromFile(const FName: String);
  end;

  TForm1 = class(TForm)
    btnAdd: TButton;
    btnShow: TButton;
    btnLoad: TButton;
    OpenDialog1: TOpenDialog;
    SaveDialog1: TSaveDialog;
    btnSave: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnAddClick(Sender: TObject);
    procedure btnShowClick(Sender: TObject);
    procedure btnLoadClick(Sender: TObject);
    procedure btnSaveClick(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    Catalogue: TCatalogue;
  end;

implementation

// Einen AnsiString in einen Stream schreiben, Länge als Integer davor schreiben
function WriteString(const AString: AnsiString; AStream: TStream): Integer;
  var
    Len: Integer;
begin
  Len := Length(AString); // Länge bestimmen
  AStream.Write(Len,SizeOf(Len)); // Länge schreiben
  Result := AStream.Write(PAnsiChar(AString)^,Len); // Daten schreiben
end;

// Einen AnsiString aus einem Stream lesen, die Länge steht als Integer davor
function ReadString(var AString: AnsiString; AStream: TStream): Integer;
  var
    Len: Integer;
begin
  AStream.Read(Len,SizeOf(Len)); // Länge lesen
  SetLength(AString,Len); // Speicher holen
  Result := AStream.Read(PAnsiChar(AString)^,Len); // Daten lesen
end;

{ TVoc }

constructor TVoc.Create(const ASource, ADest: AnsiString; const ADesc: AnsiString = '');
begin
  inherited Create;
  FSource := ASource;
  FDest := ADest;
  FDesc := ADesc;
end;

constructor TVoc.CreateFromStream(AStream: TStream);
begin
  inherited Create;
  ReadFromStream(AStream);
end;

function TVoc.Dump: AnsiString;
begin
  Result := Format('S:%s, D:%s, C:%s',[FSource,FDest,FDesc]);
end;

procedure TVoc.ReadFromStream(AStream: TStream);
begin
  ReadString(FSource,AStream);
  ReadString(FDest,AStream);
  ReadString(FDesc,AStream);
end;

procedure TVoc.WriteToStream(AStream: TStream);
begin
  WriteString(FSource,AStream);
  WriteString(FDest,AStream);
  WriteString(FDesc,AStream);
end;

{ TCatalogue }

procedure TCatalogue.LoadFromFile(const FName: String);
  var
    FS: TFileStream;
begin
  FS := TFileStream.Create(FName,fmOpenRead or fmShareDenyWrite);
  try
    LoadFromStream(FS);
  finally
    FS.Free;
  end;
end;

procedure TCatalogue.LoadFromStream(AStream: TStream);
  var
    ItemsToLoad, i: Integer;
begin
  Clear;
  AStream.Read(ItemsToLoad,SizeOf(ItemsToLoad));
  for i := 0 to ItemsToLoad-1 do
    Add(TVoc.CreateFromStream(AStream));
end;

procedure TCatalogue.SaveToFile(const FName: String);
  var
    FS: TFileStream;
begin
  if FileExists(FName) then
    DeleteFile(FName);
  FS := TFileStream.Create(FName,fmCreate or fmShareExclusive);
  try
    SaveToStream(FS);
  finally
    FS.Free;
  end;
end;

procedure TCatalogue.SaveToStream(AStream: TStream);
  var
    ItemsToWrite, i: Integer;
begin
  ItemsToWrite := Count;
  AStream.Write(ItemsToWrite,SizeOf(ItemsToWrite));
  for i := 0 to Count-1 do
    TVoc(Items[i]).WriteToStream(AStream);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Catalogue := TCatalogue.Create;
end;

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

procedure TForm1.btnAddClick(Sender: TObject);
  var
    Source, Dest, Desc: AnsiString;
begin
  Source := InputBox('Add','Source','Source');
  Dest := InputBox('Add','Dest','Dest');
  Desc := InputBox('Add','Desc','');
  Catalogue.Add(TVoc.Create(Source,Dest,Desc));
end;

procedure TForm1.btnShowClick(Sender: TObject);
  var
    i: Integer;
begin
  for i := 0 to Catalogue.Count-1 do
    ShowMessage(TVoc(Catalogue.Items[i]).Dump);
end;

procedure TForm1.btnLoadClick(Sender: TObject);
begin
  if OpenDialog1.Execute then
    Catalogue.LoadFromFile(OpenDialog1.FileName);
end;

procedure TForm1.btnSaveClick(Sender: TObject);
begin
  if SaveDialog1.Execute then
    Catalogue.SaveToFile(SaveDialog1.FileName);
end;
cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
Mashalla Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 48

Windows 7 Professional
Delphi 7 Enterprise, Turbo Delphi Explorer 2006
BeitragVerfasst: Mi 03.02.10 00:08 
Naja, immerhin sind meine Kommentare besser XD

Danke, hast du des jetzt schnell runtergetippt? Falls ja, weiß ich ja, wo ich mal hinkommen muss =) Aber warum löschst du beim Speichern in die Datei die Datei, wenn sie bereits existiert? Filestream.Create öffnet sie doch dann ... oder würde der dann dahinter die Daten einfügen?
Xentar
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 2077
Erhaltene Danke: 2

Win XP
Delphi 5 Ent., Delphi 2007 Prof
BeitragVerfasst: Mi 03.02.10 00:10 
user profile iconMashalla hat folgendes geschrieben Zum zitierten Posting springen:
Danke, hast du des jetzt schnell runtergetippt? Falls ja, weiß ich ja, wo ich mal hinkommen muss =) Aber warum löschst du beim Speichern in die Datei die Datei, wenn sie bereits existiert? Filestream.Create öffnet sie doch dann ... oder würde der dann dahinter die Daten einfügen?

Er würde die Daten schon überschreiben statt anhängen. Aber, wenn die "neuen" Daten kürzer sind als die alten, bleibt nen Überhang von alten Daten zurück.

_________________
PROGRAMMER: A device for converting coffee into software.
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Mi 03.02.10 00:17 
Moin!

user profile iconMashalla hat folgendes geschrieben Zum zitierten Posting springen:
Danke, hast du des jetzt schnell runtergetippt?
Jup, hab aber zwischendurch noch schnell was gegessen. :lol:

user profile iconMashalla hat folgendes geschrieben Zum zitierten Posting springen:
Falls ja, weiß ich ja, wo ich mal hinkommen muss =)
Nunja :? eigentlich bin ich ja der keinen-Quelltext-liefern-Prediger :roll: aber da du bereits Eigeninitiative gezeigt hast und das Thema Streams brauchbar umsetzen wirklich nicht ganz einfach ist, hilft ein komplettes Beispiel mehr, als da einzeln an den Funktionen zu popeln. :nixweiss: Das ist also kein Standard hier, sondern eine Ausnahme wegen der Streams. :idea:

user profile iconMashalla hat folgendes geschrieben Zum zitierten Posting springen:
Aber warum löschst du beim Speichern in die Datei die Datei,
Hat user profile iconXentar ja schon beantwortet. ;)

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Mi 03.02.10 00:46 
Man kann aber auch nach dem Schreiben St4ream.Size := Stream.Position; setzen. Das hat den gleichen Effekt, vermeidet aber im Zweifelsfalle, dass die Datei auf dem Datenträger kreuz-und-Quer-Alloziiert wird und beugt damit der Defragmentierung etwas vor.

_________________
Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.