Autor |
Beitrag |
gerd8888
      
Beiträge: 205
Erhaltene Danke: 3
Win7
Delphi 10.1 Starter (kostenlos) Lazarus
|
Verfasst: 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.)
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 public 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:=0; end 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], st_laenge); 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); 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
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: 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. 
|
|
Andreas L.
      
Beiträge: 1703
Erhaltene Danke: 25
Windows Vista / Windows 10
Delphi 2009 Pro (JVCL, DragDrop, rmKlever, ICS, EmbeddedWB, DEC, Indy)
|
Verfasst: So 15.01.12 18:58
Warum nicht gleich eine TStringList?
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 
      
Beiträge: 205
Erhaltene Danke: 3
Win7
Delphi 10.1 Starter (kostenlos) Lazarus
|
Verfasst: 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 (  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 Narses: Beiträge zusammengefassteinen 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
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 15.01.12 19:25
Eigentlich halte ich davon zwar nichts, aber für den Zweck bietet sich ein Record an: Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7:
| type TExample = packed record Contents: array[0..7] of 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 
      
Beiträge: 205
Erhaltene Danke: 3
Win7
Delphi 10.1 Starter (kostenlos) Lazarus
|
Verfasst: 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 Narses: Beiträge zusammengefasstDas 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
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 15.01.12 20:54
gerd8888 hat folgendes geschrieben : | 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.
Wenn du Delphi 2009 oder höher hast, brauchst du das, wenn du eine Ansidatei schreiben willst (warum?).
Dein Problem liegt aber ganz woanders: Delphi-Quelltext 1:
| fs.Write (SaveString[1], st_laenge); | 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): 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..7] of 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 public end;
var Form181: TForm181;
implementation
{$R *.dfm}
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 
      
Beiträge: 205
Erhaltene Danke: 3
Win7
Delphi 10.1 Starter (kostenlos) Lazarus
|
Verfasst: 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.
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.
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 Narses: Delphi-Tags hinzugefügt
|
|
jaenicke
      
Beiträge: 19315
Erhaltene Danke: 1747
W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: So 15.01.12 23:14
gerd8888 hat folgendes geschrieben : | 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.
gerd8888 hat folgendes geschrieben : | 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.
|
|
|