Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Filestream, string anhängen (https://www.delphipraxis.net/106799-filestream-string-anhaengen.html)

eLse-maestro 16. Jan 2008 22:26


Filestream, string anhängen
 
Hi leute,
Ich bin am verzweifeln ..

Ich möchte einen string an eine datei anhängen, und mit der datei den string auslesen..

dieser code klappt super..
Ich habe hier einen string angehangen, und direkt wieder ausgelesen..
Delphi-Quellcode:
var fs:tfilestream; s,s1:string;i:integer;
begin

  fs:=tfilestream.Create('C:\background.exe',
   fmOpenReadWrite or fmShareExclusive);
  try
    i:=fs.Seek(0, soFromEnd);
    s:='[test]';
    fs.Write(s,sizeOf(s));
    fs.Seek(i, soFromBeginning);
    fs.Read(s1,sizeOf(s1));
    showmessage(s1);

  finally
    fs.Free;
  end;
so.. jetzt wollte ich aber den string von einer anderen EXE auslesen (später dann die background.exe)

Delphi-Quellcode:
var fs:tfilestream; s1:string; i:integer;
begin

  fs:=tfilestream.Create('background.exe',
  fmOpenReadWrite or fmShareExclusive);
  try
    i=fs.Seek(0, soFromEnd);
    fs.Seek(i-4,soFromBeginning); //minus 4, weil der string 4 byte hat, und dort die andere datei auch den string ausliest.
    fs.Read(s1,sizeOf(s1));
    showmessage(s1);
  finally
    fs.Free;
und dann kommt immer eine zugriffsverletztung, und ich habe schon alles probiert :(

Vielleicht kann mir ja einer helfen, vielen dank.

mfg
else_

PS:
es soll später einen "builder" geben, der an die exe ein pfad von einem hintergrund hängt, und wenn man die exe ausführt, dass der hintergrund, der im builder eingestellt wurde, geändert wird..

HannosG 16. Jan 2008 22:37

Re: Filestream, string anhängen
 
Zitat:

Zitat von eLse-maestro
TFileStream.Create('test',fmOpenReadWrite or fmShareExclusive);

Vielleicht existiert die Datei 'test' einfach nicht :stupid:

MfG,
Hanno

BUG 16. Jan 2008 22:39

Re: Filestream, string anhängen
 
Wenn du
Delphi-Quellcode:
var fs:tfilestream; s,s1:string;i:integer;
begin

  fs:=tfilestream.Create('C:\background.exe',
   fmOpenReadWrite or fmShareExclusive);
  try
    i:=fs.Seek(0, soFromEnd);
    s:='[test]';
    fs.Write(s,sizeOf(s));
    s:=''; // hier s leerst
    fs.Seek(i, soFromBeginning);
    fs.Read(s1,sizeOf(s1));
    showmessage(s1);

  finally
    fs.Free;
  end;
wirst du merken, dass die Funktion nicht wirklich das macht was du erwartest...

Strings in Delphi könnte man auch vereinfacht als Zeiger auf einen Adressbereich sehen. Du schreibst also nicht die Zeichenkette in die Datei, sondern den Zeiger darauf.

MfG,
Bug

eLse-maestro 16. Jan 2008 22:46

Re: Filestream, string anhängen
 
@hannos, nein daran lag es nicht, hatte es nur vergessen zum schluss zu editieren.. (gemacht :) )

das mit dem zeiger kann sehr gut sein, auf die idee bin ich noch gar nicht gekommen..
wie kann ich denn das ganze umgehen?
mit einem byte array?
damit habe ich mich noch nicht beschäftigt...

Muetze1 16. Jan 2008 23:19

Re: Filestream, string anhängen
 
Delphi-Quellcode:
if s <> '' then
  fs.Write(s[1], length(s));
alternativ

Delphi-Quellcode:
if s <> '' then
  fs.Write(PChar(s)^, length(s));
alternativ

Delphi-Quellcode:
if s <> '' then
  fs.Write(Pointer(s)^, length(s));

eLse-maestro 17. Jan 2008 13:00

Re: Filestream, string anhängen
 
Delphi-Quellcode:
if s <> '' then
  fs.Write(PChar(s)^, length(s));
habe ich probiert, sowie die anderen beispiele.. aber ich bekomme immer noch eine fehler meldung beim auslesen..
fs.read
Delphi-Quellcode:
    fs.Read(s1,length(s));

marabu 17. Jan 2008 13:08

Re: Filestream, string anhängen
 
Hi,

hier eine Detailstudie:

Delphi-Quellcode:
var
  fs: TFileStream;
  fn, s: string;
begin
  s := 'Die Lust zu gehorchen befriedigt der Deutsche an einer roten Ampel'
     + sLineBreak;
  fn := 'c:\temp\test-stream.txt';
  fs := TFileStream.Create(fn, fmCreate);
  fs.Write(s[1], Length(s));
  s := '?'; // Length(s) = 1
  fs.Free;
  fs := TFileStream.Create(fn, fmOpenRead);
  SetLength(s, fs.Size); // omit for disaster
  fs.Read(s[1], fs.Size);
  fs.Free;
  ShowMessage(s);
end;
Grüße vom marabu

Muetze1 17. Jan 2008 13:09

Re: Filestream, string anhängen
 
Zitat:

Zitat von eLse-maestro
Delphi-Quellcode:
if s <> '' then
  fs.Write(PChar(s)^, length(s));
habe ich probiert, sowie die anderen beispiele.. aber ich bekomme immer noch eine fehler meldung beim auslesen..
fs.read
Delphi-Quellcode:
    fs.Read(s1,length(s));

Man könnte Analogien sehen - man könnte, muss man aber nicht.

Wenn das Schreiben des Strings nicht funktioniert, wenn man direkt den String angibt und einem schon zuvor gesagt wurde, dass man nur die Adresse in den Stream schreibt, dann könnte man vermuten, dass es beim auslesen wohl genauso ist.

Also Maestro, das bekommste nach diesem Zaunpfahl doch bestimmt vom Lesen auf's Schreiben übertragen, oder?

@marabu: das wäre dann der nächste Schritt gewesen...

eLse-maestro 17. Jan 2008 13:33

Re: Filestream, string anhängen
 
ah vielen dank,
ja ich bin ja auch nicht einer der direkt nachfragt..
aber im internet habe ich nur unbrauchbares gefunden, und in meinem buch (jetzt lerne ich delphi)
steht es mir zu ungenau drin, und sonst habe ich nur was mit byte arrays gefunden.
aber ehrlich gesagt trau ich mich nur an einen code den ich auch versteh..

und ich wusste nicht das man vor dem lesen erst den filestream wieder freigeben muss..

dankschön nochmal

marabu 17. Jan 2008 13:39

Re: Filestream, string anhängen
 
Zitat:

Zitat von eLse-maestro
... und ich wusste nicht das man vor dem lesen erst den filestream wieder freigeben muss ...

Das interpretierst du falsch, es geht natürlich auch so:

Delphi-Quellcode:
begin
  // ...
  fs.Position := 0;
  //  fs.Free;
  //  fs := TFileStream.Create(fn, fmOpenRead);
  // ...
end;
Durch fs.Free wird der Stream aber auf die Festplatte geschrieben.

Jens Schumann 17. Jan 2008 14:18

Re: Filestream, string anhängen
 
Hallo,
Du könntest einen der beiden TStream Nachfahren verwenden
Delphi-Quellcode:
unit Streaming;

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);
  WriteBuffer(aStrLen,SizeOf(Integer));
  WriteBuffer(Pointer(aStr)^,aStrLen);
end;

function TFileStreamExt.ReadStringFromStream: String;
var
   aStrLen : Integer;
begin
  ReadBuffer(aStrLen,SizeOf(Integer));
  SetLength(Result,aStrLen);
  ReadBuffer(Pointer(Result)^,aStrLen);
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.

Muetze1 17. Jan 2008 15:51

Re: Filestream, string anhängen
 
Zitat:

Zitat von himitsu

Nun rate mal, was SetLength() intern vorher aufruft?
Auch wäre es recht unwahrscheinlich, das ein eben mit leer initialisierter Result(-string) sich schon den leeren Platz mit einem anderen String teilt, oder?

himitsu 17. Jan 2008 16:21

Re: Filestream, string anhängen
 
macht SetLength das nicht nur bei Größenänderung?

[edit]
ok, dachte SetLength püft vorher ob sich überhaupt was an der Länge ändert,

aber *grad nachgesehn* es macht das nicht °_°



Zitat:

Auch wäre es recht unwahrscheinlich, das ein eben mit leer initialisierter Result(-string) sich schon den leeren Platz mit einem anderen String teilt, oder?
ja, aber nicht unmöglich ... wir hatten grad erst soeinen Fall hier in der DP, wo ein nicht initialisiertet String schon Daten enthielt.

> http://www.delphipraxis.net/internal...ght=initial%2A

HannosG 17. Jan 2008 16:31

Re: Filestream, string anhängen
 
Ob es nun unelegant ist oder nicht, habe ich mal alles andere an Zeigern und PChar und ...
außer acht gelassen, um nochmal direkt auf den 1. Beitrag zurückzukommen.

Delphi-Quellcode:
function GetFileStrFromEnd(FileName: String; Count: Integer): String;
var
  FS: TFileStream;
  I:integer;
begin
  FS:=tfilestream.Create(FileName, fmOpenReadWrite or fmShareExclusive);
  try
    I:=FS.Seek(0, soFromEnd);
    FS.Seek(I-Count,soFromBeginning);
    Setlength(Result,Count);     // nicht vergessen, sonst Zugriffsverletzung
    FS.Read(Result[1],Count);    // [1] nicht vergessen, sonst Zugriffsverletzung
  finally
    fs.Free;
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
ShowMessage( GetFileStrFromEnd('C:\background.exe', 4) );
end;
So läuft das ganze bei mir ohne Probleme.

MfG,
Hanno

himitsu 17. Jan 2008 16:50

Re: Filestream, string anhängen
 
Zitat:

Zitat von HannosG
So läuft das ganze bei mir ohne Probleme.

probier mal Count=0


muß ja nicht gleich negativ sein ... so knallt's auch schon genug :stupid:

HannosG 17. Jan 2008 17:06

Re: Filestream, string anhängen
 
Klar, ich weiß, das ist die Variante, die sich eben auf den ersten Beitrag bezieht.
Aber du musst ja auch nicht Count=0 übergeben.

Ich hab Count=0 mal ausprobiert, und auch ein paar negative Werte.
Ergebnis ist immer nicht mehr und nicht weniger als ''. (vielleicht Zufall)
Bei Count>FS.Size bekomme ich schon komische Werte heraus.

Nunja, man kann den Code dahingehend noch beliebig verbessern und ausbauen, das Grundprinzip funktioniert aber bei den richtigen Count-Angaben.

Muetze1 17. Jan 2008 17:09

Re: Filestream, string anhängen
 
1. Alle TStream Nachfahren haben eine Eigenschaft Delphi-Referenz durchsuchenTStream.Size
2. Warum seekst du auf eine Position 0 vom Ende aus gesehen um dann danach von vorne zu seeken? Warum seekst du nicht gleich auf Count Bytes vom Ende aus? So ist es völlige Resourcenverschwendung
3. Was macht dein Code, wenn die Datei kleiner ist als die mit Count angegebene Datengröße?

Also nochmal das Ganze:
Delphi-Quellcode:
function GetFileStrFromEnd(FileName: String; Count: Integer): String;
var
  FS: TFileStream;
  I:integer;
begin
  FS:=tfilestream.Create(FileName, fmOpenReadWrite or fmShareExclusive);
  try
    if FS.Seek(Count, soFromEnd) = Count then
    begin
      Setlength(Result,Count);     // nicht vergessen, sonst Zugriffsverletzung
      FS.Read(Result[1],Count);    // [1] nicht vergessen, sonst Zugriffsverletzung
    end
    else
      result := ''; // stream ist kleiner
  finally
    fs.Free;
  end;
end;
/EDIT: zweite Seite übersehen. Also wurde der 3. Punkt schon erwähnt...

HannosG 17. Jan 2008 17:23

Re: Filestream, string anhängen
 
Zu 2. :
Das kommt vom 1. Beitrag :angel2: .
Nee, sorry, gut dass du das bemerkt hast!

EDIT: hmmm, dein Code gibt bei mir immer '' aus :( .

HannosG 17. Jan 2008 17:46

Re: Filestream, string anhängen
 
So gehts... :)

Delphi-Quellcode:
function GetFileStrFromEnd(FileName: String; Count: Integer): String;
var
  FS: TFileStream;
  I:integer;
begin
  FS:=tfilestream.Create(FileName, fmOpenReadWrite or fmShareExclusive);
  try
    if (FS.Size>Count) and (Count>0) then
    begin
      FS.Seek(FS.Size-Count,soFromBeginning);
      Setlength(Result,Count);     // nicht vergessen, sonst Zugriffsverletzung
      FS.Read(Result[1],Count);    // [1] nicht vergessen, sonst Zugriffsverletzung
    end
    else
      begin
      result := ''; // stream<Count oder count<=0
      end;
  finally
    fs.Free;
  end;
end;

HannosG 17. Jan 2008 17:49

Re: Filestream, string anhängen
 
oder mit
Delphi-Quellcode:
FS.Seek(-1*Count,soFromEnd);

Muetze1 17. Jan 2008 19:37

Re: Filestream, string anhängen
 
Zitat:

Zitat von HannosG
oder mit
Delphi-Quellcode:
FS.Seek(-1*Count,soFromEnd);

Ich war bisher der Meinung, dass die Angaben positiv sein müssen bei soFromEnd - aber gut, dann halt negativ. Aber warum führst du nun noch eine Multikplikation durch, anstatt einfach nur den negativen Wert zu übergeben? Also einfach -Count angeben im Seek...

Aber ich habe eben nochmal geschaut, Seek will trotzdem ein negativen Wert haben. Die Origin Angabe ist nur der Ausgangspunkt, bewirkt aber nichts an der Bedeutung des Offsets (ausser bei soFromBeginning, dort wird der Wert dann als unsigned interpretiert laut WinAPI).

Hier dann nochmal mein korrigierter Code:

Delphi-Quellcode:
function GetFileStrFromEnd(FileName: String; Count: Integer): String;
var
  FS: TStream;
  I: integer;
begin
  result := ''; // stream ist kleiner

  FS := TFileStream.Create(FileName, fmOpenReadWrite or fmShareExclusive);
  try
    if FS.Seek(-Count, soFromEnd) = FS.Size - Count then
    begin
      Setlength(Result,Count);
      FS.Read(Result[1],Count);
    end;
  finally
    fs.Free;
  end;
end;

eLse-maestro 17. Jan 2008 21:49

Re: Filestream, string anhängen
 
Delphi-Quellcode:
function GetFileStrFromEnd(FileName: String): String;
var
  FS: TStream;
  I,count: integer;
 
begin
count:=0;
  result := ''; // stream ist kleiner

  FS := TFileStream.Create(FileName, fmOpenReadWrite or fmShareExclusive);
  try
    while pos('[data]',result)=0 do
      begin
        if FS.Seek(-Count, soFromEnd)=fs.Size then exit    \\ noch ein fehler drin
        else                                               \\ schaue morgen danach, Gute Nacht.
          begin
            if FS.Seek(-Count, soFromEnd) = FS.Size - Count then
            begin                                              
               Setlength(Result,Count);
               FS.Read(Result[1],Count);
            end;
            inc(count);
          end;
      end;
  finally
    fs.Free;
  end;
end;

habe mal muetzes code angepasst.. villeicht brauch das ja jemand..
mein string fängt mit '[data]' an.

und irgendwie wollte meine if anweisung kein "if not count=fs.size then..." aktzeptieren, dann habe ich es mal so gedreht ;)

himitsu 17. Jan 2008 22:10

Re: Filestream, string anhängen
 
Delphi-Quellcode:
if not (count = fs.Size) then

//oder besser

if count <> fs.Size then

if count < fs.Size then
Delphi-Quellcode:
function GetFileStrFromEnd(FileName: String): String;
var
  FS: TStream;
  I,count: integer;
 
begin
count:=0;
  result := ''; // stream ist kleiner

  FS := TFileStream.Create(FileName, fmOpenReadWrite or fmShareExclusive);
  try
    while (count <= fs.Size) and (pos('[data]',result) = 0) do
    begin
      if FS.Seek(-Count, soFromEnd) = FS.Size - Count then
      begin
        Setlength(Result,Count);
        FS.Read(Result[1],Count);
      end;
      inc(count);
    end;
    if pos('[data]',result) = 0 then result := ''; // fals string nicht gefunden wurde
  finally
    fs.Free;
  end;
end;
wie groß ist deine Datei, bzw. wie lang ist der String maximal, den du suchst?

so ließt du ja die Datei mehrmals vom Ende her ein ... Length(Result)-mal

Count=0 wurd es eh nicht geben und wenn dein String mit [data] anfängt, dann kannst bei der Vorgehensweise du auch gleich bei count=Length('[data]'); oder count=6; anfangen, den kürzer kann der String nicht sein.


falls die Maximalläge nicht feststeht und du nicht immer einen genügendgroßen Block auslesen willst, dann
könnte man auch in größeren Schritten zurückgehn (nicht nur 1 > inc(count), sondern gleich ein paar byte mehr



oder du ließt gleich nur einmal einen größer Block (ganze Datei, oder soviel wie der String maximal lanhg ist) aus, suchst darin den Stringanfang und kopierst dir ab dem Fundort den String bis Datei-/Blockende in Result rein.
Delphi-Quellcode:
FS.Seek(-1024, soFromEnd); // 1024 = 1 KB
SetLength(Result, 1024);
FS.Read(Result[1], 1024);
Result := Copy(Result, Pos('[data]', Result), 1024);
// statt Copy  Delete(Result, 1, Pos('[data]', Result) - 1);



erstellst du die Datei selber?
wenn ja, dann speicher doch die Stringgröße (siehe oben), dann kannst die Auslesen und du weißt wo der String ist.

Dieses Länge/Größe kann man auch nach dem String speichern (nicht immer nur davor, wie oben sichtbar)
Delphi-Quellcode:
FS.Seek(-SizeOf(Len), soFromEnd);
FS.Read(Len, SizeOf(Len));
FS.Seek(-SizeOf(Len) - Len, soFromEnd);
SetLength(Result, Len);
FS.Read(Result[1], Len);

> alles in Kurz und ohne Fehlerprüfung und sowas

eLse-maestro 17. Jan 2008 22:16

Re: Filestream, string anhängen
 
das problem ist, das der string mal so mal so lang ist, und nicht konstant..

mir kommt aber gerade die idee, das der "builder" ja die zeichen länge des strings anhängen kann.. dann kann man das auslesen
und die while schleife weg lassen..

die datei ist so um die 400kb groß, also um ressourcen mache ich mir nicht so große gedanken..

gute nacht :)

himitsu 17. Jan 2008 22:25

Re: Filestream, string anhängen
 
Delphi-Quellcode:
function GetFileStrFromEnd(FileName: String): String;
var
  FS: TStream;
  i: integer;
 
begin
  FS := TFileStream.Create(FileName, fmOpenRead or fmShareExclusive);
  try
    if FS.Size > 0 then
    begin
      FS.Position := 0;
      SetLength(Result, FS.Size);
      FS.Read(Result[1], FS.Size);
      i := Pos('[data]', Result);
      if i > 0 then Delete(Result, 1, i - 1) else Result := '';
    end
    else
      Result := '';
  finally
    FS.Free;
  end;
end;
wenn du das [data] nicht willst, dann einfach bei "i - 1" diese Länge einrechnen, also "i + 5"


und für die idealere Variante (siehe dem Code mit 1024 im letzten Beitrag), ... und dort einfach einen Wert wählen, der auf jeden Fall groß genug ist ^^

Muetze1 18. Jan 2008 00:33

Re: Filestream, string anhängen
 
Ich würde bei sowas eher MMF (memory mapped filestream) verwenden, damit solltest du das viel schneller lesen, also dieses blockweise "von hinten nach vorne seeken".


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:24 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-2025 by Thomas Breitkreuz