Delphi-PRAXiS
Seite 1 von 2  1 2   

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Delphi IniFile ReadBinaryStream bekomme ich nicht in Gange (https://www.delphipraxis.net/198422-inifile-readbinarystream-bekomme-ich-nicht-gange.html)

KodeZwerg 1. Nov 2018 08:11

IniFile ReadBinaryStream bekomme ich nicht in Gange
 
Hallo Community,
ich bekomme immer einen "Stream write error" beim Versuch einen Stream aus einer Ini-Datei zu lesen.

Woran kann das liegen? Ich bin mehreren Beispielen gefolgt aber entdecke einfach nicht was da falsch läuft.
Vielleicht hat jemand Rat für mich.

Hier meine bisherige Bastelei:
Delphi-Quellcode:
//unit IniHelper;
uses
  Windows, SysUtils, Classes, SHFolder, IniFiles;

...

function GetSpecialFolderPath( Folder: Integer ): string;
//const SHGFP_TYPE_CURRENT = 0;
var
  Path: Array [0..MAX_PATH] of WideChar;
begin
  if Windows.Succeeded( SHFolder.SHGetFolderPathW( 0, Folder, 0, SHGFP_TYPE_CURRENT, @Path[ 0 ] ) ) then
    Result := Path
   else
    Result := '';
end;

function ReadIniStream( const Filename, Section, Ident: String; const FolderOverride: String = '' ): TStream;
var
  FIniFile: TIniFile;
  Check: Integer;
  FName: String;
  MS: TStream;
begin
  FName := GetSpecialFolderPath( CSIDL_LOCAL_APPDATA );
  if FName = '' then
    Exit;
  if FolderOverride = '' then
    FName := FName + '\' + SysUtils.ChangeFileExt( SysUtils.ExtractFilename( ParamStr( 0 ) ), '.' ) + '\' + Filename
   else
    FName := FName + '\' + FolderOverride + '\' + Filename;
  if not FileExists( FName ) then
    Exit;
  FIniFile := TIniFile.Create( FName );
  try
    MS := TMemoryStream.Create();
    try
      FIniFile.ReadBinaryStream( Section, Ident, MS );
      MS.Position := 0;
      Result.CopyFrom( MS, MS.Size );
      Result.Position := 0;
    finally
      MS.Free;
    end;
  finally
    FIniFile.Free;
  end;
end;

function WriteIniStream( const Filename, Section, Ident: String; const Value: TStream; const FolderOverride: String = '' ): Boolean;
var
  FIniFile: TIniFile;
  FName: String;
begin
  Result := False;
  FName := GetSpecialFolderPath( CSIDL_LOCAL_APPDATA );
  if FName = '' then
    Exit;
  if FolderOverride = '' then
    FName := FName + '\' + SysUtils.ChangeFileExt( SysUtils.ExtractFilename( ParamStr( 0 ) ), '.' )
   else
    FName := FName + '\' + FolderOverride;
  if not SysUtils.ForceDirectories( FName ) then
    Exit;
  if Value.Size = 0 then
    Exit;
  FIniFile := TIniFile.Create( FName + '\' + Filename );
  try
    Value.Position := 0;
    FIniFile.WriteBinaryStream( Section, Ident, Value );
  finally
    FIniFile.Free;
    Result := True;
  end;
end;
und entsprechende Aufrufe
Delphi-Quellcode:
procedure TForm1.btnReadClick(Sender: TObject);
var
  S: String;
  ms: TStream;
begin
  ms := TMemoryStream.Create();
  try
    S := 'Stream-Error';
    ms := IniHelper.ReadIniStream( 'Testfile.cfg', 'Setup', 'StreamEntry' );
    S := IntToStr( ms.Size );
    Memo1.Lines.Add( 'Stream-Size: ' + S );
    ms.Free;
  except
    Memo1.Lines.Add( 'Stream-Size: ' + S );
    ms.Free;
  end;
end;

procedure TForm1.btnWriteClick(Sender: TObject);
var
  s: String;
  ms: TStream;
begin
  try
    ms := TMemoryStream.Create();
    try
      S := 'This is a Stream.';
      ms.WriteBuffer( S[1], Length( S ) * 2 );
      ms.Position := 0;
      if WriteIniStream( 'Testfile.cfg', 'Setup', 'StreamEntry', ms ) then
        begin
          Memo1.Lines.Add( 'StreamEntry Saved.' )
        end
        else
        begin
          Memo1.Lines.Add( 'Error: Testfile.cfg Stream could not be created.' )
        end;
    finally
      ms.Free;
    end;
  except
    Memo1.Lines.Add( 'Error: Fatal Error.' )
  end;
end;
Danke fürs Lesen.

Ps: Speichern klappt, hat nur eine Leseschwäche, genau wie ich :-]

TiGü 1. Nov 2018 08:17

AW: IniFile ReadBinaryStream bekomme ich nicht in Gange
 
Wenn du jetzt noch das Result in ReadIniStream initialisierst/erzeugst/den Konstruktor aufrufst, haste es.
Nimm ruhig noch einen Kaffee, es kann nicht schaden! :cheers:

KodeZwerg 1. Nov 2018 08:24

AW: IniFile ReadBinaryStream bekomme ich nicht in Gange
 
Lol, jupp Danke klappt!

/edit
für die Nachwelt, so isses nu :]
Delphi-Quellcode:
function ReadIniStream( const Filename, Section, Ident: String; const FolderOverride: String = '' ): TStream;
var
  FIniFile: TIniFile;
  FName: String;
begin
  FName := GetSpecialFolderPath( CSIDL_LOCAL_APPDATA );
  if FName = '' then
    Exit;
  if FolderOverride = '' then
    FName := FName + '\' + SysUtils.ChangeFileExt( SysUtils.ExtractFilename( ParamStr( 0 ) ), '.' ) + '\' + Filename
   else
    FName := FName + '\' + FolderOverride + '\' + Filename;
  if not FileExists( FName ) then
    Exit;
  FIniFile := TIniFile.Create( FName );
  try
    Result := TMemoryStream.Create();
    try
      FIniFile.ReadBinaryStream( Section, Ident, Result );
    finally
      Result.Position := 0;
    end;
  finally
    FIniFile.Free;
  end;
end;

p80286 1. Nov 2018 09:38

AW: IniFile ReadBinaryStream bekomme ich nicht in Gange
 
Und Du bist Dir sicher, daß das richtigfunktionier?

verkürzt hast Du:
Delphi-Quellcode:
Funktion Read:TStream;
begin
  if abbruch then Exit;
  Result:=TStream.Create;
end;

//Tuwas
MyStream:TStream;

MyStream:=TStream.Create;
MyStream:=Read;
...
MyStream.Free;
Wenn Deine er Funktion erfolgreich ist, dann nagelst Du einen zweiten Stream über den ersten oder was?
Das sieht mir sehr nach einem Memory-leak aus.

Mach es mit einer Procedure (
Delphi-Quellcode:
read(const mystream:TStream)
) und Du bist auf der sicheren Seite.

Gruß
K-H

KodeZwerg 1. Nov 2018 12:03

AW: IniFile ReadBinaryStream bekomme ich nicht in Gange
 
Liste der Anhänge anzeigen (Anzahl: 1)
Ich hab in dem btnReadClick() Aufruf das Create weggelassen. Ich lade bald hoch, will noch ne verschlüßelung einbauen.

für interessierte, das ist es bis jetzt.

/edit
habs im anhang als komplettes demo projekt zusammengeschnürrt.
beim entschlüsseln klappt irgendwas noch nicht, bin an der sache dran.

Ps: keine speicherlecks gefunden

Hobbycoder 1. Nov 2018 13:22

AW: IniFile ReadBinaryStream bekomme ich nicht in Gange
 
Trotzdem hätte ich das so gemacht (wie p80286 schon sagte):
Delphi-Quellcode:
function ReadIniStream( const Filename, Section, Ident: String; const IniStream: TStream; const FolderOverride: String = '' ): Boolean;
var
  FIniFile: TIniFile;
  FName: String;
  FMemStream: TMemoryStream;
begin
  Result:=False;
  if IniStream<>nil then
  begin
    FMemStream := TMemoryStream.Create();
    try
      FName := GetIniFilename( Filename, FolderOverride );
      if not SysUtils.FileExists( FName ) then
        Exit;
      FIniFile := TIniFile.Create( FName );
      FIniFile.ReadBinaryStream( Section, Ident, FMemStream );
      FMemStream.Position := 0;
      IniStream.Position := 0;
      IniStream.CopyFrom(FMemStream, SizeOf(FMemStream));
      Result:=True;
    finally
      FMemStream.Free;
      IniStream.Position := 0;
    end;
  end;
end;
Zumindest ungefähr so (hab ich nicht in Delphi getestet).

Der Grund ist folgender:
Zum einen vertrete ich die Einstellung: Wer etwas erzeugt, der gibt's auch frei.
Zum anderen wird zwar in deiner jetzigen Version der Rssultstream auf jeden Fall erzeugt, aber sollte in beim Lesen aus der Ini was schief gehen, gibt sie trotzdem irgendwas zurück. Die aufrufende Methode erfährt davon nichts, und muss dann mit den fehlerhaften Daten weiterarbeiten.

Mit o.g. Lösung hätte man schon mal die Info, ob das Lesen des Streams fehlerfrei war. Nun muss man zwar in der aufrufenden Methode den Stream erzeugen (wieder eine Zeile mehr), aber damit erhöht sich m.M.n. die Übersichtlichkeit an der Stelle, wo ich den Stream dann auch wieder freigeben muss.

Ist aber nur meine Meinung ;-)

KodeZwerg 1. Nov 2018 14:15

AW: IniFile ReadBinaryStream bekomme ich nicht in Gange
 
Dann ist ja fast wie beim ersten mal ^_^
Habe Ratschlag angenommen und umgesetzt:

so in der IniHelper.pas
Delphi-Quellcode:
function ReadIniStream( const Filename, Section, Ident: String; const Value: TStream; const FolderOverride: String = '' ): Boolean;
var
  FIniFile: TIniFile;
  FName: String;
  FMS: TMemoryStream;
begin
  Result := False;
  if ( Value <> nil ) then
    begin
      FMS := TMemoryStream.Create();
      try
        FName := GetIniFilename( Filename, FolderOverride );
        if not SysUtils.FileExists( FName ) then
          Exit;
        FIniFile := TIniFile.Create( FName );
        try
          FIniFile.ReadBinaryStream( Section, Ident, FMS );
          FMS.Position := 0;
          Value.Position := 0;
          Value.CopyFrom( FMS, FMS.Size );
        finally
          FIniFile.Free;
          Value.Position := 0;
          Result := True;
        end;
      finally
        FMS.Free;
      end;
    end;
end;
und so in der demo
Delphi-Quellcode:
  ms := TMemoryStream.Create();
  try
    S := 'Stream-Error';
    if IniHelper.ReadIniStream( 'Testfile.cfg', 'Setup', 'StreamEntry', ms ) then
      begin
        S := IntToStr( ms.Size );
        Memo1.Lines.Add( 'Stream-Size: ' + S );
        S := '';
        SetLength( S, ms.Size div 2 );
        ms.Read( S[1], ms.Size );
        Memo1.Lines.Add( 'Stream: ' + S );
        ms.Free;
      end
      else
        Memo1.Lines.Add( 'Stream-Error: ' + S );
  except
    Memo1.Lines.Add( 'Stream-Error: ' + S );
    ms.Free;
  end;

Fritzew 1. Nov 2018 14:32

AW: IniFile ReadBinaryStream bekomme ich nicht in Gange
 
Zitat:

Zitat von KodeZwerg (Beitrag 1417248)
Habe Ratschlag angenommen und umgesetzt:
und so in der demo

Wenn schon dann so.
Ansonsten gibst Du Deinen Stream nicht frei wenn IniHelper.ReadIniStream mit false zurückkommt
Delphi-Quellcode:
  ms := TMemoryStream.Create();
      try
         try
            S := 'Stream-Error';
            if IniHelper.ReadIniStream('Testfile.cfg', 'Setup', 'StreamEntry', ms) then
               begin
                  S := IntToStr(ms.Size);
                  Memo1.Lines.Add('Stream-Size: ' + S);
                  S := '';
                  SetLength(S, ms.Size div 2);
                  ms.Read(S[1], ms.Size);
                  Memo1.Lines.Add('Stream: ' + S);

               end
            else
               Memo1.Lines.Add('Stream-Error: ' + S);
         finally
            ms.Free;
         end;
      except
         Memo1.Lines.Add('Stream-Error: ' + S);
      end;

KodeZwerg 1. Nov 2018 17:45

AW: IniFile ReadBinaryStream bekomme ich nicht in Gange
 
Liste der Anhänge anzeigen (Anzahl: 1)
Oh ja, wie wahr! Nun noch mal gefixte version, verschlüßelung funktioniert nun auch :-)

Danke fürs drauf Aufmerksam machen!

Luckie 1. Nov 2018 17:54

AW: IniFile ReadBinaryStream bekomme ich nicht in Gange
 
Wohl eher Base64 codiert oder? Zumindest hatte ich bei dir im Codecwas mit base64 gesehen.


Alle Zeitangaben in WEZ +1. Es ist jetzt 16:38 Uhr.
Seite 1 von 2  1 2   

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