Autor Beitrag
gerd8888
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 205
Erhaltene Danke: 3

Win7
Delphi 10.1 Starter (kostenlos) Lazarus
BeitragVerfasst: Sa 09.07.11 15:14 
Hallo,

ich schreibe in einer Datei of char das Wort 'Hallo'
datei: file of char

Das ist nun in der textdatei.txt mit einem texteditor zu sehen.

Wenn ich aber nun diese Datei mit der TStringlist bearbeite: loadfromfile(textdatei.txt) und diese dann TStringlist.text
ausleseen will, kommt anstatt 'Hallo' der Buchstabe 'E'.

Wenn ich hinterher, die textdatei.txt mit einem texteditor oeffne und abspeichere, funktioniert alles.

Aber ich will nicht jedesmal die Datei oeffnen und abspeichern. Daher die Frage, wie kann man das Problem loesen?

Gerd
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19311
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 09.07.11 15:34 
In Anbetracht der Fülle an Informationen (keine Delphiversion im Profil, kein Quelltext, ...) rate ich einmal ein wenig...

Ich vermute du hast Delphi 2009 oder höher. Heißt Char ist ein Unicodezeichen. Dann fehlt dir das Byte-Order-Mark am Anfang der Datei.

Wozu überhaupt die Spielerei mit file of char? Warum machst du es nicht gleich richtig, sei es nun mit einer TStringList oder anders? :gruebel:
gerd8888 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 205
Erhaltene Danke: 3

Win7
Delphi 10.1 Starter (kostenlos) Lazarus
BeitragVerfasst: Sa 09.07.11 16:11 
Ich benutzte Delphi 2009.
Ich will folgendes machen: Ich will Daten speichern, Name... Text ... usw.
Normalerweise waehlt man die typisierte Form mit record. Das Problem hierbei ist, dass der Text unterschiedliche Groesse hat.
Einmal ist er nur 3 Zeichen und beim andernmal 10000 Zeichen lang. Also ist ein text:string[10000] nicht die sinnvollste Loesung.

Deshalb will alles in einer typisierten file of char schreiben. (Man kann auch mit seek Buchstabe fuer Buchstabe schnell auslesen)
Anfangs- und Endposition speichere ich in einer anderen typisierten Datei ab. Darum brauche ich das File of char.

Das ist das Spielchen, das ich gerade mache. Somit ist es praktisch dynamisch typisiert.

Wie setze ich den Byte-Order-Mark?

Gerd
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19311
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 09.07.11 16:21 
Das BOM brauchst du nur, wenn du eine normal lesbare Unicodetextdatei erstellen willst. Wenn du die Daten einfach nur speichern willst, brauchst du das nicht, dann ist es aber auch vollkommen egal, dass du die Datei im Editor nicht lesen kannst.

Nimm einfach einen TFileStream zur Datenspeicherung. Dazu jeweils Klassen, in denen du die Daten hast, mit je einer Methode LoadFromStream zum Laden der Daten und SaveToStream zum Speichern der Daten in einenTStream, fertig. ;-)

user profile icongerd8888 hat folgendes geschrieben Zum zitierten Posting springen:
Normalerweise waehlt man die typisierte Form mit record.
Du vielleicht, ich mit Sicherheit nicht. ;-)
gerd8888 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 205
Erhaltene Danke: 3

Win7
Delphi 10.1 Starter (kostenlos) Lazarus
BeitragVerfasst: Sa 09.07.11 17:05 
Wie speicherst Du Daten ab, die Du schnell wieder finden möchtest?
Wenn Du das ganze nur als Textdatei abspeicherst, musst du jedesmal mit readln() dich Zeile für Zeile durchschlagen.
Und andere Methoden kenne ich nicht.
haentschman
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 285
Erhaltene Danke: 33


DX10 Berlin Professional
BeitragVerfasst: Sa 09.07.11 17:14 
Zitat:
Wie speicherst Du Daten ab, die Du schnell wieder finden möchtest?

... in ner Datenbank ?
Zitat:
Ich will Daten speichern, Name... Text ... usw.

... der Klassiker.

PS: Je nach Datenmenge und Zugriff kommen diverse DB in Frage. Persönlich würde ich auch bei wenig Datensätzen diese Variante vorziehen, da man sich über das Speichern (wo / wie) keine Gedanken machen muß. Letztendlich holt man sich die Informationen raus wie man sie braucht.

8)
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19311
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 09.07.11 17:30 
Ich benutze da in der Regel wie gesagt einen einfachen TFileStream. Gerade wenn es um extrem schnelle Zugriffe mit genau definierten Daten geht, kann das deutlich schneller als eine general purpose Datenbank sein.

Die allgemeine Methode ist aber wie bereits genannt wurde einfach eine Datenbank wie SQlite für kleinere Projekte oder Firebird (Embedded) für größere Projekte.

Meine Lösung sähe so ca. aus, wenn du keine echte Datenbank nutzen möchtest:
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:
type
  TMyData = class
  private
    FTest: string;
    FValue: Integer;
  public
    procedure SaveToStream(AStream: TStream);
    procedure LoadFromStream(AStream: TStream);
    property Test: string read FTest write FTest;
    property Value: Integer read FValue write FValue;
  end;

[...]

function LoadStringFromStream(AStream: TStream): String;
var
  ResultString: AnsiString;
  StringSize: Integer;
begin
  Result := '';
  if AStream.Size - AStream.Position < SizeOf(StringSize) then
    Exit;
  AStream.ReadBuffer(StringSize, SizeOf(StringSize));
  SetLength(ResultString, StringSize);
  if AStream.Size - AStream.Position < StringSize then
    Exit;
  AStream.ReadBuffer(Pointer(ResultString)^, StringSize);
  {$ifdef UNICODE} // ab Delphi 2009
  Result := Utf8ToString(ResultString);
  {$else}
  Result := Utf8Decode(ResultString);
  {$endif}
end;

procedure SaveStringToStream(AStream: TStream; AString: String);
var
  StringSize: Integer;
  StringToSave: AnsiString;
begin
  StringToSave := Utf8Encode(AString);
  StringSize := Length(StringToSave);
  AStream.WriteBuffer(StringSize, SizeOf(StringSize));
  AStream.WriteBuffer(Pointer(StringToSave)^, StringSize);
end;

procedure TMyData.LoadFromStream(AStream: TStream);
begin
  FTest := LoadStringFromStream(AStream);
  AStream.ReadBuffer(FValue, SizeOf(FValue));
end;

procedure TMyData.SaveToStream(AStream: TStream);
begin
  SaveStringToStream(AStream, FTest);
  AStream.WriteBuffer(FValue, SizeOf(FValue));
end;

// Nutzung:
var
  FileContents: TFileStream;
  MyTest: TMyData;
begin
  FileContents := TFileStream.Create(...);
  try
    MyTest := TMyData.Create;
    try
      MyTest.Test := 'blabla';
      MyTest.SaveToStream(FileContents);
    finally
      MyTest.Free;
    end;
  finally
    FileContents.Free;
  end;
end;
Das lässt sich natürlich noch beliebig schachteln usw.

Zum Beispiel in einer generischen Liste von Daten:
ausblenden 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:
type
  TMyDataList = class(TObjectList<TMyData>)
  public
    procedure SaveToStream(AStream: TStream);
    procedure LoadFromStream(AStream: TStream);
  end;

[...]

procedure TMyDataList.LoadFromStream(AStream: TStream);
var
  CurrentData: TMyData;
  i, DataCount: Integer;
begin
  AStream.ReadBuffer(DataCount, SizeOf(DataCount));
  for i := 0 to DataCount - 1 do
  begin
    CurrentData := TMyData.Create;
    CurrentData.LoadFromStream(AStream);
  end;
end;

procedure TMyDataList.SaveToStream(AStream: TStream);
var
  CurrentData: TMyData;
begin
  AStream.WriteBuffer(Count, SizeOf(Count));
  for CurrentData in Self do
    CurrentData.SaveToStream(AStream);
end;
Ungetestet im Browser getippt, Tippfehler schenke ich dir. :D
gerd8888 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 205
Erhaltene Danke: 3

Win7
Delphi 10.1 Starter (kostenlos) Lazarus
BeitragVerfasst: Sa 09.07.11 19:39 
Du musst aber bei TFileStream auch beim schreiben vorher mit sizeof(..) ihm die Groesse mitteilen.
Somit ist es vom Prinzip auch typisiert!
Es ist jetzt praktisch verschlüsselt (ist das eine Art Binärdatei?) in der Datei.
Das ist doch so gesehen der einzige Unterschied.
Schade, dass er das nicht wie eine textdatei speichert. Oder geht das auch?

Deinen Code würde ich ja gerne mal testen, leider bin ich mit TFileStream noch ungeübt.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19311
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Sa 09.07.11 20:54 
user profile icongerd8888 hat folgendes geschrieben Zum zitierten Posting springen:
Schade, dass er das nicht wie eine textdatei speichert. Oder geht das auch?
Wenn du das willst, solltest du die Daten lieber im CSV-Format oder als XML speichern. ;-)

user profile icongerd8888 hat folgendes geschrieben Zum zitierten Posting springen:
Deinen Code würde ich ja gerne mal testen, leider bin ich mit TFileStream noch ungeübt.
Du kannst den ersten Code so wie er ist einfach kopieren und den Code zum Benutzen in einen Buttonklick legen.
gerd8888 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 205
Erhaltene Danke: 3

Win7
Delphi 10.1 Starter (kostenlos) Lazarus
BeitragVerfasst: So 10.07.11 13:31 
Ich habe gerade versucht Deinen Code einzubauen.
Funktioniert bei mir nicht. Was ist falsch:

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:
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    FTest: string;
    FValue: Integer;
  public
    procedure SaveToStream(AStream: TStream);
    procedure LoadFromStream(AStream: TStream);
    property Test: string read FTest write FTest;
    property Value: Integer read FValue write FValue;
  end;

var Form1:TForm1;

implementation

 {$R *.dfm}

function LoadStringFromStream(AStream: TStream): String;
var
  ResultString: AnsiString;
  StringSize: Integer;
begin
  Result := '';
  if AStream.Size - AStream.Position < SizeOf(StringSize) then
    Exit;
  AStream.ReadBuffer(StringSize, SizeOf(StringSize));
  SetLength(ResultString, StringSize);
  if AStream.Size - AStream.Position < StringSize then
    Exit;
  AStream.ReadBuffer(Pointer(ResultString)^, StringSize);
  {$ifdef UNICODE} // ab Delphi 2009
  Result := Utf8ToString(ResultString);
  {$else}
  Result := Utf8Decode(ResultString);
  {$endif}
end;

procedure SaveStringToStream(AStream: TStream; AString: String);
var
  StringSize: Integer;
  StringToSave: AnsiString;
begin
  StringToSave := Utf8Encode(AString);
  StringSize := Length(StringToSave);
  AStream.WriteBuffer(StringSize, SizeOf(StringSize));
  AStream.WriteBuffer(Pointer(StringToSave)^, StringSize);
end;

procedure TForm1.Button1Click(Sender: TObject);
// Nutzung:
var
  FileContents: TFileStream;
  MyTest: TForm1;
  path, path_f:string;
begin
  path := ExtractFilePath(ParamStr(0));
  path_f:=path+'datei1.txt';
  FileContents := TFileStream.Create(path_f,fmopenreadwrite);
  try
    MyTest := TForm1.Create;
    try
      MyTest.Test := 'blabla';
      MyTest.SaveToStream(FileContents);
    finally
      MyTest.Free;
    end;
  finally
    FileContents.Free;
  end;
end;

procedure TForm1.LoadFromStream(AStream: TStream);
begin
  FTest := LoadStringFromStream(AStream);
  AStream.ReadBuffer(FValue, SizeOf(FValue));
end;

procedure TForm1.SaveToStream(AStream: TStream);
begin
  SaveStringToStream(AStream, FTest);
  AStream.WriteBuffer(FValue, SizeOf(FValue));
end;



end.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19311
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 10.07.11 14:35 
Was heißt "funktioniert nicht"? Meinst du den fehlenden Parameter beim TForm.Create?

Davon abgesehen ist es Quatsch das in das Formular einzubauen. Du willst ja nicht das Formular neu erzeugen und speichern sondern deine Daten...
Kopiere doch einfach den Quelltext wirklich 1:1... :roll:
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:
unit Unit1;

interface

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

type
  TMyData = class
  private
    FTest: string;
    FValue: Integer;
  public
    procedure SaveToStream(AStream: TStream);
    procedure LoadFromStream(AStream: TStream);
    property Test: string read FTest write FTest;
    property Value: Integer read FValue write FValue;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
  public
  end;

var Form1:TForm1;

implementation

 {$R *.dfm}

function LoadStringFromStream(AStream: TStream): String;
var
  ResultString: AnsiString;
  StringSize: Integer;
begin
  Result := '';
  if AStream.Size - AStream.Position < SizeOf(StringSize) then
    Exit;
  AStream.ReadBuffer(StringSize, SizeOf(StringSize));
  SetLength(ResultString, StringSize);
  if AStream.Size - AStream.Position < StringSize then
    Exit;
  AStream.ReadBuffer(Pointer(ResultString)^, StringSize);
  {$ifdef UNICODE} // ab Delphi 2009
  Result := Utf8ToString(ResultString);
  {$else}
  Result := Utf8Decode(ResultString);
  {$endif}
end;

procedure SaveStringToStream(AStream: TStream; AString: String);
var
  StringSize: Integer;
  StringToSave: AnsiString;
begin
  StringToSave := Utf8Encode(AString);
  StringSize := Length(StringToSave);
  AStream.WriteBuffer(StringSize, SizeOf(StringSize));
  AStream.WriteBuffer(Pointer(StringToSave)^, StringSize);
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  FileContents: TFileStream;
  MyTest: TMyData;
  path, path_f: string;
begin
  path := ExtractFilePath(ParamStr(0));
  path_f := path + 'datei1.txt';
  FileContents := TFileStream.Create(path_f, fmOpenReadWrite);
  try
    MyTest := TMyData.Create;
    try
      MyTest.Test := 'blabla';
      MyTest.SaveToStream(FileContents);
    finally
      MyTest.Free;
    end;
  finally
    FileContents.Free;
  end;
end;

procedure TMyData.LoadFromStream(AStream: TStream);
begin
  FTest := LoadStringFromStream(AStream);
  AStream.ReadBuffer(FValue, SizeOf(FValue));
end;

procedure TMyData.SaveToStream(AStream: TStream);
begin
  SaveStringToStream(AStream, FTest);
  AStream.WriteBuffer(FValue, SizeOf(FValue));
end;

end.
gerd8888 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 205
Erhaltene Danke: 3

Win7
Delphi 10.1 Starter (kostenlos) Lazarus
BeitragVerfasst: So 10.07.11 16:08 
ja danke, so funktioniert es bei mir. Mir war schon klar, dass ich da wieder was falsch gemacht habe.

Du hast gesagt, dass man das auch als Text speichern könnte. Was muss man ändern.
Ich habe Dir ja gesagt, dass ich mich mit dem TStream nicht auskenne.
Du schreibst also mit writebuffer und liest mit readbuffer aus. Das habe ich verstanden.

Jetzt habe ich lediglich nur einen String abgespeichert.
Jetzt will ich einen Datensatz bestehend aus 2 Edit-Feldern abschliessend mit Button2 erzeugen
1 Name1
2 Name2

und dann den 2. Datensatz auslesen. Kannst Du weiterhelfen?

Da ich das Prinzip nicht kenne eine Frage:
Bei einer Datenbank mit Tstringlist muss ich die gesamten Daten in den Speicher laden.

Das muss ich bei TFileStream nicht? Ich kann hier direkt von der Datei den gewünschten Bereich auslesen?
Und wie sieht das beim speichern aus. Muss man da vorher die gesamte Datei oeffnen?

Gerd
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19311
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 10.07.11 17:11 
user profile icongerd8888 hat folgendes geschrieben Zum zitierten Posting springen:
Du hast gesagt, dass man das auch als Text speichern könnte. Was muss man ändern.
Naja, dann musst du dir überlegen in welchem Format du speichern möchtest (UTF-8, Unicode, ...) und dann entweder entsprechend umwandeln (UTF-8 ) oder das Byte-Order-Mark als erstes in die Datei schreiben, wenn die leer ist (Unicode).

user profile icongerd8888 hat folgendes geschrieben Zum zitierten Posting springen:
Jetzt will ich einen Datensatz bestehend aus 2 Edit-Feldern abschliessend mit Button2 erzeugen
1 Name1
2 Name2

und dann den 2. Datensatz auslesen. Kannst Du weiterhelfen?
Du meinst wie du an den zweiten Datensatz kommst? Das lässt sich auf verschiedene Arten machen, je nach Datenmenge.
Du kannst z.B. einen Dateiheader als erstes speichern, in dem du nicht nur Metadaten über die Datei speicherst (Version, Datenanzahl, ...), sondern auch ein Inhaltsverzeichnis. Dann kannst du darüber direkt auf die Daten zugreifen. Das lohnt aber nur bei größeren Datenmengen.

Wenn es sehr schnell sein soll, bietet sich evtl. auch ein Zugriff via Memory-Mapped-Files an.

user profile icongerd8888 hat folgendes geschrieben Zum zitierten Posting springen:
Da ich das Prinzip nicht kenne eine Frage:
Bei einer Datenbank mit Tstringlist muss ich die gesamten Daten in den Speicher laden.
Ja, grundsätzlich, dafür kannst du im Speicher aber auch Einträge zwischen anderen hinzufügen und löschen.

user profile icongerd8888 hat folgendes geschrieben Zum zitierten Posting springen:
Das muss ich bei TFileStream nicht? Ich kann hier direkt von der Datei den gewünschten Bereich auslesen?
Ja, sicher. Dafür kannst du Position setzen und ab dort lesen. Du musst nur wissen wo die Position ist, eben z.B. durch ein Inhaltsverzeichnis.

user profile icongerd8888 hat folgendes geschrieben Zum zitierten Posting springen:
Und wie sieht das beim speichern aus. Muss man da vorher die gesamte Datei oeffnen?
Wenn du in der Mitte einen Eintrag änderst, bleiben zwei Möglichkeiten:
Entweder ab der entsprechenden Position auslesen und den Rest neu speichern oder den Eintrag als gelöscht markieren und einfach anhängen. Das geht natürlich nur, wenn die Dateigröße auch ein wenig größer werden darf und es reicht die Datei ab und zu zu optimieren. Zudem darf die Datenreihenfolge keine Rolle spielen.

Bei neu Einfügen ebenso:
Wenn die Reihenfolge keine Rolle spielt, kann der Eintrag einfach angehängt werden.

Allgemein noch zur Wahl der Zugriffsmethode:
Wenn die Datenmenge so groß wird, dass ein komplettes Einlesen der Datei zu lange dauert, bietet sich vermutlich eher eine echte Datenbank an...
Diese Art der einfachen Speicherung in einer Datei bietet sich immer dort an, wo die Daten beim Start komplett in den Arbeitsspeicher geladen werden und dann zwischendurch oder am Ende wieder gespeichert werden.
gerd8888 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 205
Erhaltene Danke: 3

Win7
Delphi 10.1 Starter (kostenlos) Lazarus
BeitragVerfasst: Mo 11.07.11 15:50 
Zitat:
Naja, dann musst du dir überlegen in welchem Format du speichern möchtest (UTF-8, Unicode, ...) und dann entweder entsprechend umwandeln (UTF-8 ) oder das Byte-Order-Mark als erstes in die Datei schreiben, wenn die leer ist (Unicode).

Ich würde es am liebsten so haben, dass ich es auch mit einem texteditor öffnen kann.
Was eignet sich da? UTF-8?
Und was muss ich dann einfügen?
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19311
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mo 11.07.11 16:35 
Naja, das kommt eben drauf an wie du es in der Datei haben willst... Woher soll ich das denn wissen? :nixweiss:
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:
unit Unit1;

interface

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

type
  TMyData = class
  private
    FTest: string;
    FValue: Integer;
  public
    procedure SaveToStream(AStream: TStream);
    property Test: string read FTest write FTest;
    property Value: Integer read FValue write FValue;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
  public
  end;

var Form1:TForm1;

implementation

 {$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
const
  ByteOrderMark: WORD = $FEFF;
var
  FileContents: TFileStream;
  MyTest: TMyData;
  path, path_f: string;
  InitFile: Boolean;
begin
  path := ExtractFilePath(ParamStr(0));
  path_f := path + 'datei1.txt';
  InitFile := not FileExists(path_f);
  if InitFile then
    FileContents := TFileStream.Create(path_f, fmCreate)
  else
    FileContents := TFileStream.Create(path_f, fmOpenReadWrite);
  try
    if InitFile then
      FileContents.WriteBuffer(ByteOrderMark, SizeOf(ByteOrderMark))
    else
      FileContents.Position := FileContents.Size;
    MyTest := TMyData.Create;
    try
      MyTest.Test := 'blabla';
      MyTest.SaveToStream(FileContents);
    finally
      MyTest.Free;
    end;
  finally
    FileContents.Free;
  end;
end;

procedure TMyData.SaveToStream(AStream: TStream);
var
  CurrentData: string;
begin
  CurrentData := '"' + FTest + '";"' + IntToStr(FValue) + '"' + sLineBreak;
  AStream.WriteBuffer(PChar(CurrentData)^, Length(CurrentData) * SizeOf(Char));
end;

end.
Du kannst natürlich auch das CSV-Format als solches implementieren oder das ganz anders speichern... wie du eben möchtest...
gerd8888 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 205
Erhaltene Danke: 3

Win7
Delphi 10.1 Starter (kostenlos) Lazarus
BeitragVerfasst: Mi 13.07.11 22:59 
Das funktioniert bei mir. So habe ich es mir vorgestellt.
AStream.WriteBuffer(PChar(CurrentData)^, Length(CurrentData) * SizeOf(Char));
Du hast doch jetzt hier keine konkrete Laengenangabe. Wenn ich jetzt nur in einer Zeile so reinschreibe, dann lege ich mir ein Inhaltsverzeichnis an. Und dann kann ich, wenn ich Dich richtig verstanden habe mit Position jedes Element ausfindig machen.
Wie würdest Du das machen?
Und Dein sLineBreak;
Bringt der was von der Suche. Kann man dann auch irgendwie Zeilen auslesen?
gerd8888 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 205
Erhaltene Danke: 3

Win7
Delphi 10.1 Starter (kostenlos) Lazarus
BeitragVerfasst: Do 14.07.11 00:32 
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:
  unit Unit1;

interface

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

type
  TMyData = class
  private
    FTest: string;
    FValue: Integer;
  public
    procedure SaveToStream(AStream: TStream);
    procedure LoadFromStream(AStream: TStream);
    property Test: string read FTest write FTest;
    property Value: Integer read FValue write FValue;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
  public
  end;

var Form1:TForm1;

implementation

 {$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
const
  ByteOrderMark: WORD = $FEFF;
var
  FileContents: TFileStream;
  MyTest: TMyData;
  path, path_f: string;
  InitFile: Boolean;
begin
  path := ExtractFilePath(ParamStr(0));
  path_f := path + 'datei1.txt';
  InitFile := not FileExists(path_f);
  if InitFile then
    FileContents := TFileStream.Create(path_f, fmCreate)
  else
    FileContents := TFileStream.Create(path_f, fmOpenReadWrite);
  try
    if InitFile then
      FileContents.WriteBuffer(ByteOrderMark, SizeOf(ByteOrderMark))
    else
      FileContents.Position := FileContents.Size;
    MyTest := TMyData.Create;
    try
      MyTest.Test := 'blabla';
      mytest.Value:=3;
      MyTest.SaveToStream(FileContents);
    finally
      MyTest.Free;
    end;
  finally
    FileContents.Free;
  end;
end;

function LoadStringFromStream(AStream: TStream): String;
var
  ResultString: AnsiString;
  StringSize: Integer;
begin
  Result := '';
  if AStream.Size - AStream.Position < SizeOf(StringSize) then
    Exit;
  AStream.ReadBuffer(StringSize, SizeOf(StringSize));
  SetLength(ResultString, StringSize);
  if AStream.Size - AStream.Position < StringSize then
    Exit;
  AStream.ReadBuffer(Pointer(ResultString)^, StringSize);
  {$ifdef UNICODE} // ab Delphi 2009
  Result := Utf8ToString(ResultString);
  {$else}
  Result := Utf8Decode(ResultString);
  {$endif}
  form1.label1.caption:='W'+result;
end;

procedure TMyData.SaveToStream(AStream: TStream);
var
  CurrentData: string;
begin
  CurrentData := '"' + FTest + '";"' + IntToStr(FValue) + '"' + sLineBreak;
  AStream.WriteBuffer(PChar(CurrentData)^, Length(CurrentData) * SizeOf(Char));
end;

procedure TMyData.LoadFromStream(AStream: TStream);
begin
  FTest := LoadStringFromStream(AStream);
  //form1.Label1.Caption:=ftest;
  AStream.ReadBuffer(FValue, SizeOf(FValue));
end;

procedure TForm1.Button2Click(Sender: TObject);
var FileContents:TFilestream;
    MyTest:TMydata;
    path, path_f:string;
begin
  path := ExtractFilePath(ParamStr(0));
  path_f := path + 'datei1.txt';
  {InitFile := not FileExists(path_f);
  if InitFile then
    FileContents := TFileStream.Create(path_f, fmCreate)
  else}

    FileContents := TFileStream.Create(path_f, fmOpenReadWrite);
  //  FileContents.Position := FileContents.Size;
    MyTest := TMyData.Create;

     // MyTest.Test := 'blabla';
     // mytest.Value:=3;
    MyTest.LoadfromStream(FileContents);

    MyTest.Free;

    FileContents.Free;
end;

end.


Wenn ich jetzt den Button2 drücke bekomme ich nicht ausgelesen.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19311
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Do 14.07.11 05:50 
Naja, das Laden ist da nicht so einfach. Da musst du dann immer bis zum Zeilenende lesen. Wenn du es dir einfach machen willst, nimm eine TStringList und lade damit die Datei. Dann sollte noch AssignFile, Reset, ReadLn, ... gehen, und natürlich selbst implementieren wie z.B. hier von mir:
www.delphi-forum.de/viewtopic.php?t=99933

Einen bestimmten Datensatz gezielt auslesen ist natürlich unmöglich, wenn du eine solche normale Textdatei hast.

Aber wenn es per Hand lesbar und änderbar sein soll, bleibt ja nichts weiter als ein solches Format, auch wenn es logischerweise deutlich langsamer als ein Binärformat ist. :nixweiss: