Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi TFileStream Problem (https://www.delphipraxis.net/49367-tfilestream-problem.html)

kurtm1 10. Jul 2005 12:23


TFileStream Problem
 
Ich glaube ich bin gerade unfähig:
Ich möchte eine String Variable ganz normal abspeichern (mittels TFilestream)

Delphi-Quellcode:
var Settings:TFileStream;
var ini:String;
[..]
        if not FileExists('settings.txt') then
        Settings:=TFileStream.Create('settings.txt', fmcreate)
        else
        Settings:=TFileStream.Create('settings.txt', fmopenwrite);
        Settings.Write(ini,sizeof(ini));
        Settings.Free;
und einlesen mache ich so:
Delphi-Quellcode:
var Settings:TFileStream;
var str:String;
[..]
        if not FileExists('settings.txt') then
        ShowMessage('Keine Preset Datei gefunden')
        else
        begin
        Settings:=TFileStream.Create('settings.txt', fmopenread);
        Settings.Read(str,sizeof(settings));
        Settings.Free;
        end;
Kann wir wer sagen, wo der Fehler liegt?

Jens Schumann 10. Jul 2005 12:32

Re: TFileStream Problem
 
Hallo,
es handelt sich eigentlich nicht um einen Fehler. Die Huge-Strings sind hier Schuld.
Delphi-Quellcode:
var
  ini : String;
...
  SizeOf(ini); // liefert als Ergebnis 4.
..
in der Variablen ini ist nur eine Referenz (Zeiger) auf den String gespeichert.
Deshalb musst beim Schreiben und Lesen von Strings in einen Stream wie folgt vorgehen.
D.h. ich habe mir mal zwei Streamnachfahren gebastelt
Delphi-Quellcode:
interface

uses Sysutils, Classes;

Type

  TMemoryStreamExt = class(TMemoryStream)
  public
    procedure WriteStringToStream(aStr : String);
    function ReadStringFromStream : String;
  end;

  TFileStreamExt = class(TFilestream)
  public
    procedure WriteStringToStream(aStr : String);
    function ReadStringFromStream : String;
  end;



implementation


{ TFileStreamExt }

procedure TFileStreamExt.WriteStringToStream(aStr : String);
var
   aStrLen : Integer;
begin
  aStrLen:=Length(aStr); // Länge des Strings holen
  WriteBuffer(aStrLen,SizeOf(Integer)); // Länge des Strings in den Stream schreiben
  WriteBuffer(Pointer(aStr)^,aStrLen); // Den eigentlichen String in den Stream schieben
end;

function TFileStreamExt.ReadStringFromStream: String;
var
   aStrLen : Integer;
begin
  ReadBuffer(aStrLen,SizeOf(Integer)); // Länge des Strings aus Stream lesen
  SetLength(Result,aStrLen); // Länge des Strinsg setzen
  ReadBuffer(Pointer(Result)^,aStrLen); // Stringdaten aus Stream lesen
end;

{ TMemoryStreamExt }

function TMemoryStreamExt.ReadStringFromStream: String;
var
   aStrLen : Integer;
begin
  ReadBuffer(aStrLen,SizeOf(Integer));
  SetLength(Result,aStrLen);
  ReadBuffer(Pointer(Result)^,aStrLen);
end;

procedure TMemoryStreamExt.WriteStringToStream(aStr: String);
var
   aStrLen : Integer;
begin
  aStrLen:=Length(aStr);
  WriteBuffer(aStrLen,SizeOf(Integer));
  WriteBuffer(Pointer(aStr)^,aStrLen);
end;


end.

Taladan 10. Jul 2005 12:35

Re: TFileStream Problem
 
Bei einer nicht bekannten Datei, weiß er natürlich nicht, wie viel er auslesen soll, da dieser Eert beim start ja noch auf Null steht. Daher mußte die Länge der Datei mit abspeichern.

Delphi-Quellcode:
var Settings:TFileStream;
var ini:String;
var length : integer;
[..]
        if not FileExists('settings.txt') then
        Settings:=TFileStream.Create('settings.txt', fmcreate)
        else
        Settings:=TFileStream.Create('settings.txt', fmopenwrite);
        length := sizeof(ini);
        Settings.Write(length, sizeof(length));
        Settings.Write(ini,i);
        Settings.Free;
und einlesen mache ich so:
Delphi-Quellcode:
var Settings:TFileStream;
var str:String;
var length: integer;
[..]
        if not FileExists('settings.txt') then
        ShowMessage('Keine Preset Datei gefunden')
        else
        begin
        Settings:=TFileStream.Create('settings.txt', fmopenread);
        settings.read(length, sizeof(length));
        Settings.Read(str,length);
        Settings.Free;
        end;

Christian Seehase 10. Jul 2005 12:47

Re: TFileStream Problem
 
Moin Taladan,

Zitat:

Zitat von Taladan
Daher mußte die Länge der Datei mit abspeichern.

wozu dass?
TFileStream enthält doch die Eigenschaft Size.

@Jens:
Statt PChar(Stringvariable)^ kann man auch einfach Stringvariable[1] schreiben.

kurtm1 10. Jul 2005 12:50

Re: TFileStream Problem
 
Zitat:

Zitat von Christian Seehase
Moin Taladan,

wozu dass?
TFileStream enthält doch die Eigenschaft Size.

das frage ich mich auch

marabu 10. Jul 2005 13:03

Re: TFileStream Problem
 
Taladan hat sich gewiss überlegt, dass ein file stream für nur einen string eher selten ist. Speichert man aber mehrere strings in einem stream, dann ist es best practice die einzelnen string Längen voran zu speichern, damit die buffer allocation beim Einlesen optimal unterstützt werden kann.

Grüße vom marabu

SirThornberry 10. Jul 2005 13:04

Re: TFileStream Problem
 
Ist euch eventuell schonmal in den Sinn gekommen das mann mehre Strings in eine Datei schreiben will? Und in so einem Fall nützt mir TFileStream.Size reichlich wenig weil ich anhand der gesamtgröße nicht weiß wo welcher String aufhört!

Zur Ausgangsfrage: Wenn ein String geschrieben werden soll dann musst du das erste Zeischen angeben. Und anstelle von SizeOf solltest du bei Strings "Length" verwenden.
Zu Schreiben
Delphi-Quellcode:
var LLen: Integer;
begin
  [...]
  LLen := Length(ini);
  Settings.Write(LLen, SizeOf(LLen));
  Settings.Write(ini[1],LLen);
  [..]
zum Lesen
Delphi-Quellcode:
var LLen: Integer;
begin
  [...]
  Settings.Read(LLen, SizeOf(LLen));
  SetLength(ini);
  Settings.Read(ini[1],LLen);
  [..]

Sprint 10. Jul 2005 13:13

Re: TFileStream Problem
 
Zitat:

Zitat von kurtm1
Ich möchte eine String Variable ganz normal abspeichern (mittels TFilestream)

Mit TFileStream:
Delphi-Quellcode:
procedure WriteStringToFile(const FileName, S: String);
begin

  try
    with TFileStream.Create(FileName, fmCreate) do
      try
        if Length(S) > 0 then
          WriteBuffer(S[1], Length(S));
      finally
        Free;
      end;
  except

  end;

end;

procedure ReadStringFromFile(const FileName: String; var S: String);
begin

  SetLength(S, 0);
  try
    with TFileStream.Create(FileName, fmOpenRead) do
      try
        if Size > 0 then
        begin
          SetLength(S, Size);
          ReadBuffer(S[1], Size);
        end;
      finally
        Free;
      end;
  except

  end;

end;
Ich würde es aber ohne TFileStream machen:
Delphi-Quellcode:
procedure WriteStringToFile(const FileName, S: String);
var
  Handle: Integer;
begin

  Handle := FileCreate(FileName);
  if Handle <> -1 then
  begin
    if Length(S) > 0 then
      FileWrite(Handle, S[1], Length(S));
    FileClose(Handle);
  end;

end;

procedure ReadStringFromFile(const FileName: String; var S: String);
var
  Handle: Integer;
  Size: Integer;
begin

  SetLength(S, 0);
  Handle := FileOpen(FileName, fmOpenRead);
  if Handle <> -1 then
  begin
    Size := FileSeek(Handle, 0, soFromEnd);
    if Size > 0 then
    begin
      SetLength(S, Size);
      FileSeek(Handle, 0, soFromBeginning);
      FileRead(Handle, S[1], Size);
    end;
    FileClose(Handle);
  end;

end;

SirThornberry 10. Jul 2005 13:15

Re: TFileStream Problem
 
@sprint: deine Variante hat auch was für sich, aber ich finds schon gut das er TFileStream nimmt und sich somit gleich mit den Objecten beschäftigt anstelle von globalen Funktionen

kurtm1 10. Jul 2005 15:31

Re: TFileStream Problem
 
k danke, habs jetzt mit euren Lösungen geschafft


Alle Zeitangaben in WEZ +1. Es ist jetzt 02:55 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz