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: So 15.01.12 18:09 
Hallo,

ich habe eine Frage zu dem filestream.
1. Ich will den Text (hier die Zahlen 0-5) mit einer gewissen Textlaenge (st_laenge) in test.dat speichern.
Das funktioniert aber nur teilweise. Wenn ich die st_laenge=4 auf 4 Beschraenke steht in der test.dat "1 2 3 4 "
Genau so wie ich es haben will.
Aber bei st_laenge=8 kommt das hier: "0 1 3 2 3 4 3 5 "
Es sind 2 "3" Zahlen nicht richtig platziert.
Hier den gesamten Code.
Wichtig ist der Button1, da schreibt er das in die Datei rein. Die Datei hat Ansi-Codierung.
Die Datei test.dat muss vorher erstellt werden.
(Button2 liest aus und Button3 ueberschreibt.)

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

interface

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



type
  TForm1 = class(TForm)
    Button1: TButton;
    Label1: TLabel;
    ListBox1: TListBox;
    Button2: TButton;
    Button3: TButton;
    Label2: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}
type Tdaten=string;
const st_laenge=8;

procedure SaveStringToFile (Filename, SaveString: tdaten; npos:integer);
var
  fs: TFileStream;
begin
  fs := TFileStream.Create (Filename, fmopenreadwrite);
  try
    if npos=-1 then begin fs.size:=0; npos:=0end else
    if npos=0 then begin
      fs.Position:=fs.size;
    end else fs.Position:=(npos-1)*st_laenge;
    form1.listbox1.items.add(inttostr(fs.Size));
    if SaveString <> '' then
      fs.Write (SaveString[1]{PChar(savestring)^}, st_laenge{Length (SaveString)});
  finally
    fs.Free;
  end;
end;

procedure LoadStringFromFile(Filename: string; npos:integer; var LoadString: tdaten);
var
  fs: TFileStream;
begin
  fs := TFileStream.Create (Filename, fmOpenRead or fmShareDenyNone);
  try
    fs.Position:=(npos-1)*st_laenge;
    SetLength (LoadString, fs.size);
    //form1.listbox1.items.add(inttostr(fs.Size)+' V ');
    if fs.size>0 then
      fs.Read (LoadString[1],fs.size);
  finally
    fs.Free;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var data:tdaten;
    x:integer;
begin
  data:='0';
  savestringtofile(ExtractFilePath(Application.ExeName) + 'test.dat',data,-1);
  for x:=1 to 5 do begin
    data:= inttostr(x);
   savestringtofile(ExtractFilePath(Application.ExeName) + 'test.dat',data,0);
  end;

end;

procedure TForm1.Button2Click(Sender: TObject);
var data:tdaten;
    x:integer;
begin
  listbox1.Clear;
  for x:=1 to 4 do begin
    Loadstringfromfile(ExtractFilePath(Application.ExeName) + 'test.dat',x,data);
    listbox1.Items.Add(data);
  end;
end;

procedure TForm1.Button3Click(Sender: TObject);
var x:integer;
    data:tdaten;
begin
  x:=2;
  data:='7';
  savestringtofile(ExtractFilePath(Application.ExeName) + 'test.dat',data,2);
end;

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

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 15.01.12 18:43 
Ohne jetzt geschaut zu haben was da schief geht:
Was hast du eigentlich vor? Denn so wirklich sinnvoll sieht das nicht aus was du da machst. :gruebel:
Andreas L.
ontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic starofftopic star
Beiträge: 1703
Erhaltene Danke: 25

Windows Vista / Windows 10
Delphi 2009 Pro (JVCL, DragDrop, rmKlever, ICS, EmbeddedWB, DEC, Indy)
BeitragVerfasst: So 15.01.12 18:58 
Warum nicht gleich eine TStringList?

ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
var
  sl: TStrings;
begin
  sl := TStringList.Create;
  try
    sl.Text := '1 2 3 4 5';
    sl.SaveToFile('C:\datei.dat');
  finally
    FreeAndNil(sl);
  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 15.01.12 19:12 
Die ganzen Daten habe ich bereits auf TStringliste. Aber das will ich nicht. Ich muesste ja alles vorher komplett in den Arbeitsspeicher laden.
Ich moechte meine Daten, die jeweils aus st_laenge (8) sind, in eine Datei abspeichern und wieder aufrufen. Und zwar so, dass ich das ganze in einer Datei nicht binär, sondern als Text (aus Sicherheitsgruenden) vorfinde.
Ich habe bloss Probleme, die Strings so zu speichern, dass ich sie auch wieder lesen kann. Ansonsten wuerde es schon gehen. Nur teilweise habe ich Probleme damit.

Moderiert von user profile iconNarses: Beiträge zusammengefasst

einen filestream braucht man, um daten abzuspeichern und wieder auszulesen. jaenicke, genau das habe ich vor, nur so, dass in der datei ein leserlicher text vorzufinden ist. Also Datensaetze, die einen String von der Laenge 8 haben und das 100000-mal. Genau das habe ich vor.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 15.01.12 19:25 
Eigentlich halte ich davon zwar nichts, aber für den Zweck bietet sich ein Record an:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
type
  TExample = packed record
    Contents: array[0..7of Char;
  end;

var
  MyFile: file of TExample;
Da können natürlich auch mehrere Bestandteile im Record stehen und mit einem Klassenoperator kann man auch sehr gut damit arbeiten, wenn man den Inhalt der Einträge z.B. als ganzen String betrachten will.

Zudem kann man darin auch Eigenschaften haben, die automatisch an die richtigen Stellen im Array geschrieben werden usw., falls das nötig ist.
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 15.01.12 19:38 
den recorde im filestream hernehmen?
Ich habe keine Probleme die Daten einzulesen und auszulesen mit assign(file) usw.
Mir geht es ehrlich gesagt auch nur ein bisschen am Rumspielen vom dem streamfile.
Und waere gerne daran rein theoretisch interessiert.
Vielleicht ist es so am besten ausgedrueckt.

Moderiert von user profile iconNarses: Beiträge zusammengefasst

Das duerfte das Problem sein.
type tdaten=ansistring;

und wie welcher codierung arbeitet man, wenn man mit string arbeitet?
Zu solchen speziellen Fragen gibt es im Internet fast keine Hilfe.
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 15.01.12 20:54 
user profile icongerd8888 hat folgendes geschrieben Zum zitierten Posting springen:
Das duerfte das Problem sein.
type tdaten=ansistring;
Da du im Profil deine Delphiversion nicht ausgefüllt hast, kann ja niemand wissen, ob du eine Unicodeversion von Delphi hast. :nixweiss:
Wenn du Delphi 2009 oder höher hast, brauchst du das, wenn du eine Ansidatei schreiben willst (warum?).

Dein Problem liegt aber ganz woanders:
ausblenden Delphi-Quelltext
1:
      fs.Write (SaveString[1]{PChar(savestring)^}, st_laenge{Length (SaveString)});					
Du schreibst immer z.B. 8 Byte, auch wenn so viel in dem String gar nicht drin ist (da steht ja z.B. nur eine Zahl drin). Dementsprechend sind es zufällige Daten, die du in die Datei schreibst.

Aber ich merke schon, du magst umständliche Wege. Dann mal ein Beispiel (funktioniert nur mit Ansi, für Unicodedateien fehlt noch ein bisschen was):
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:
type
  TExample = packed record
  strict private
    var
      FContents: array[0..7of AnsiChar;
    function GetChar1: AnsiChar;
    procedure SetChar1(const Value: AnsiChar);
    procedure SetContents2(const Value: AnsiString);
    function GetContents2: AnsiString;
  public
    procedure SaveToStream(AStream: TStream);
    procedure LoadFromStream(AStream: TStream);
    property Char1: AnsiChar read GetChar1 write SetChar1;
    property Contents2: AnsiString read GetContents2 write SetContents2;
  end;

  TForm181 = class(TForm)
    btnSave: TButton;
    btnLoad: TButton;
    procedure btnSaveClick(Sender: TObject);
    procedure btnLoadClick(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

var
  Form181: TForm181;

implementation

{$R *.dfm}

{ TExample }

function TExample.GetChar1: AnsiChar;
begin
  Result := FContents[0];
end;

procedure TExample.SetChar1(const Value: AnsiChar);
begin
  FContents[0] := Value;
end;

procedure TExample.SetContents2(const Value: AnsiString);
var
  ContentsSize: Integer;
begin
  ContentsSize := SizeOf(FContents) - SizeOf(FContents[0]);
  ZeroMemory(@FContents[1], ContentsSize);
  CopyMemory(@FContents[1], PAnsiChar(Value), Min(Length(Value), ContentsSize));
end;

function TExample.GetContents2: AnsiString;
var
  ContentsSize: Integer;
begin
  ContentsSize := SizeOf(FContents) - SizeOf(FContents[0]);
  SetLength(Result, ContentsSize);
  Result := Copy(FContents, 2, ContentsSize);
end;

procedure TExample.LoadFromStream(AStream: TStream);
begin
  AStream.ReadBuffer(FContents, SizeOf(FContents));
  AStream.Seek(Length(sLineBreak), soCurrent);
end;

procedure TExample.SaveToStream(AStream: TStream);
begin
  AStream.WriteBuffer(FContents, SizeOf(FContents));
  AStream.WriteBuffer(sLineBreak, Length(sLineBreak));
end;

procedure TForm181.btnSaveClick(Sender: TObject);
var
  MyFile: TFileStream;
  CurrentEntry: TExample;
  i: Integer;
begin
  MyFile := TFileStream.Create(GetCurrentDir + '\test.txt', fmCreate);
  try
    for i := 0 to 5 do
    begin
      CurrentEntry.Char1 := AnsiChar(IntToStr(i)[1]);
      CurrentEntry.Contents2 := 'test';
      CurrentEntry.SaveToStream(MyFile);
    end;
  finally
    MyFile.Free;
  end;
end;

procedure TForm181.btnLoadClick(Sender: TObject);
var
  MyFile: TFileStream;
  CurrentEntry: TExample;
  i: Integer;
begin
  MyFile := TFileStream.Create(GetCurrentDir + '\test.txt', fmOpenRead);
  try
    while MyFile.Position < MyFile.Size do
    begin
      CurrentEntry.LoadFromStream(MyFile);
      ShowMessage(CurrentEntry.Char1);
      ShowMessage(CurrentEntry.Contents2);
    end;
  finally
    MyFile.Free;
  end;
end;
Einfach nur mit einem Knopf zum Speichern von 6 Einträgen und einen zum Laden.
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 15.01.12 22:52 
Den String bei meiner Version, kann ich ja hinterher auch mit Leerzeichen fuellen, so dass das kein Problem mehr darstellt.
Jedenfalls funktioniert meine Version jetzt einwandfrei. Auf eine Kleinigkeit beim loadstringfromfile moechte ich noch hinweisen.
ausblenden Delphi-Quelltext
1:
2:
3:
SetLength (LoadString, fs.size);
if fs.size>0 then
fs.Read (LoadString[1],fs.size);

Das fs.size muss natuerlich in fs.read durch st_laenge ersetzt werden. Das sollte aber klar sein.

Dein Code habe ich gerade getestet und funktioniert einwandfrei. Besten Dank für Deine Mühe. Wenn ich das richtig sehe, braucht man nicht unbedingt AnsiString und AnsiChar. Man kommt auch nur mit einem aus. Ich glaube du wolltest das nur mal zeigen.
Die 2 Zeilen sind mir noch unklar und der Hokus-Pokus mit dem linebreak ist mir auch neu.
ausblenden Delphi-Quelltext
1:
2:
ZeroMemory(@FContents[1], ContentsSize);
CopyMemory(@FContents[1], PAnsiChar(Value), Min(Length(Value), ContentsSize));

Ich werde mich morgen mit Deinem source code noch etwas beschaeftigen.

Und ja Delphi 2009 benutze ich.

Moderiert von user profile iconNarses: Delphi-Tags hinzugefügt
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: So 15.01.12 23:14 
user profile icongerd8888 hat folgendes geschrieben Zum zitierten Posting springen:
Wenn ich das richtig sehe, braucht man nicht unbedingt AnsiString und AnsiChar. Man kommt auch nur mit einem aus. Ich glaube du wolltest das nur mal zeigen.
Richtig, ich wollte zeigen, dass du auf diese Weise die Daten über Eigenschaften in das Array stecken und daraus lesen kannst.

Ich persönlich benutze allerdings eher Klassen und schreibe die einzelnen Bestandteile in SaveToStream einzeln in den Stream.

user profile icongerd8888 hat folgendes geschrieben Zum zitierten Posting springen:
Die 2 Zeilen sind mir noch unklar und der Hokus-Pokus mit dem linebreak ist mir auch neu.
ZeroMemory(@FContents[1], ContentsSize);
CopyMemory(@FContents[1], PAnsiChar(Value), Min(Length(Value), ContentsSize));
Ich schreibe zuerst Nullzeichen in die 7 Bytes ab dem zweiten Byte im Array und schreibe dann je nach Länge des übergebenen Strings in die Bytes ab dem zweiten die übergebenen Zeichen.