AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language TFilestream in Schleife funktioniert nur einmalig

TFilestream in Schleife funktioniert nur einmalig

Ein Thema von gabneo · begonnen am 2. Aug 2016 · letzter Beitrag vom 6. Aug 2016
Antwort Antwort
Seite 1 von 2  1 2   
gabneo

Registriert seit: 15. Okt 2006
Ort: Deutsche Toskana :)
93 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#1

TFilestream in Schleife funktioniert nur einmalig

  Alt 2. Aug 2016, 13:49
Delphi-Version: XE
Hallo,

hat jemand eine Idee warum folgender Code in der Schleife nach einem Durchlauf hängen bleibt?

Delphi-Quellcode:
for i := flist.Count-1 downto 0 do
begin
  sFilename := extractfilepath(paramstr(0)) + flist[i].NodeValue;
  sFile := TFileStream.Create(sFilename, fmCreate);
  try
    fparams.Text := 'RPC=download';
    fparams.Add('file=' + flist[i].NodeValue);
    Queue ( procedure begin Form2.log('Post'); end);
    fhttp.Post(TIdURI.URLEncode(fURL), fparams, sFile);
  finally
    fhttp.Disconnect;
    sFile.Free;
    Queue ( procedure begin Form2.log('SetFileDate'); end);
    SetFileDate(sFilename, UnixToDateTime(flist[i].Attributes['timestamp']));
    // --> hier hört er nach einem Durchlauf auf <-- das Filedate wird noch einwanfrei gesetzt....
  end;
end;
Ich vermute es gibt ein Problem mit dem Filestream und dem Beschreiben dessen durch indy (idHttp). Es gibt keine Exception. Das Programm hängt sich einfach nur auf.

Mit einem Handle hatte ich leider auch keinen Erfolg:
Delphi-Quellcode:
for i := flist.Count-1 downto 0 do
begin
  if (pos(flist[i].NodeValue + #255 + flist[i].Attributes['timestamp'], currentList.Text) > 0) then continue; //Datumsvergleich
  Queue ( procedure begin Form2.log('entry ' + inttostr(i) + ': ' + flist[i].NodeValue + #255 + flist[i].Attributes['timestamp']); end);
  //Download
  sFilename := extractfilepath(paramstr(0)) + flist[i].NodeValue;
  //sFile := TFileStream.Create(sFilename, fmCreate);
  Handle1 := CreateFile(PChar(sFilename), GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
  fileStream := THandleStream.Create(Handle1);
  try
    fparams.Text := 'RPC=download';
    fparams.Add('file=' + flist[i].NodeValue);
    Queue ( procedure begin Form2.log('Post'); end);
    fhttp.Post(TIdURI.URLEncode(fURL), fparams, fileStream); //sFile
    Queue ( procedure begin Form2.log('Nächster'); end);
  finally
    fhttp.Disconnect;
    //sFile.Free;
    fileStream.Free;
    CloseHandle(Handle1);
    //Queue ( procedure begin Form2.log('SetFileDate'); end);
    SetFileDate(sFilename, UnixToDateTime(flist[i].Attributes['timestamp']));
end;
Was mache ich falsch?
LG

Geändert von gabneo ( 2. Aug 2016 um 13:50 Uhr) Grund: Titel eindeutiger, falsche Delphi Version
  Mit Zitat antworten Zitat
Benutzerbild von p80286
p80286

Registriert seit: 28. Apr 2008
Ort: Stolberg (Rhl)
6.659 Beiträge
 
FreePascal / Lazarus
 
#2

AW: TFilestream in Schleife funktioniert nur einmalig

  Alt 2. Aug 2016, 14:03
Was passiert denn, bzw. passiert nicht wenn Du mit [F7]/[F8] da durch steppst?

Gruß
K-H
Programme gehorchen nicht Deinen Absichten sondern Deinen Anweisungen
R.E.D retired error detector
  Mit Zitat antworten Zitat
Delbor

Registriert seit: 8. Okt 2006
Ort: St.Gallen/Schweiz
1.186 Beiträge
 
Delphi 11 Alexandria
 
#3

AW: TFilestream in Schleife funktioniert nur einmalig

  Alt 2. Aug 2016, 14:17
Hi gabneo
Delphi-Quellcode:
for i := flist.Count-1 downto 0 do//<= Hier beginnst du deine Schleife
begin
  sFilename := extractfilepath(paramstr(0)) + flist[i].NodeValue;
  sFile := TFileStream.Create(sFilename, fmCreate); //<= Hier erstellst du im Programmverzeichnis, auf das du keinen Zugriff hast,
                                                     // die Datei ***
  try
    fparams.Text := 'RPC=download';
    fparams.Add('file=' + flist[i].NodeValue);
    Queue ( procedure begin Form2.log('Post'); end);
    fhttp.Post(TIdURI.URLEncode(fURL), fparams, sFile);
  finally // <= Hier leitest du einen Codeabschnitt ein, der in jedem Fall ausgeführt werden soll.
    fhttp.Disconnect; // Hier schliesst du die Verbindung.
    sFile.Free; // und gibst den Filstream frei.
    Queue ( procedure begin Form2.log('SetFileDate'); end);
    SetFileDate(sFilename, UnixToDateTime(flist[i].Attributes['timestamp']));
    // --> hier hört er nach einem Durchlauf auf <-- das Filedate wird noch einwanfrei gesetzt....
  end;
end;
Da du die http-Verbindung schon im ersten Scheifendurchlauf schliesst,ist da nichts mehr, was in der Schleife verarbeitet werden könnte. Auf jeden Falll aber wäre es sehr interessant, das Codeschnpsel zu sehen, das vor Abarbeitung der Schleife und bei/nach Verbindungsherstellung abläuft.

Gruss
Delbor

PS: *** Das Programmverzeichnis ist nach fertigsttellung deines Programmes und nach dessen Istallation C:\Programme. Und da hat kein User Zugriff darauf (seit WinXP(?)). Und deshalb wird dannzumal jeder VCersuch, da in eine Ini-Datei oder sonstwas zu schreiben, fehlschlagen.
Eine Mögliche Lösung findest du zum Beispiel hier
Roger
Man muss und kann nicht alles wissen - man muss nur wissen, wo es steht.
Frei nach Albert Einstein
http://roase.ch

Geändert von Delbor ( 2. Aug 2016 um 14:35 Uhr)
  Mit Zitat antworten Zitat
gabneo

Registriert seit: 15. Okt 2006
Ort: Deutsche Toskana :)
93 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#4

AW: TFilestream in Schleife funktioniert nur einmalig

  Alt 2. Aug 2016, 14:29
Hallo K-H,
das war schon mal ein sehr guter Hinweis. Hatte vergessen das integriertes Debuggen noch abgeschaltet war, so ist mir aufgefallen das die SSL Dlls schon mal gefehlt haben.
Ich bekomme einen EOutOfMemory 'Zu wenig Arbeitsspeicher' (siehe Screenshot) Fehler.
Zum Zeitpunkt der Fehlermeldung springt der Speicherverbrauch der Anwendung von 40 MB auf 610 MB an (Habe 16 GB insgesamt) beim Download einer 4 MB Datei.

@Delbor
Das Programmverzeichnis ist nach Auslieferung Das Lokale AppData-Verzeichnis. Es wird auch bereits fehlerfrei beschrieben.

fhttp.Disconnect; Ist drin um sicherzustellen das der Zugriff auf den Stream beendet wird. Auch wenn man das auskommentiert, ändert sich nichts. Zudem idHTTP die Verbindung mit dem nächsten fhttp.Post(... wieder aufbaut. 8 Stück schafft er jetzt in Reihe...bis eben der Arbeitsspeicher knapp wird

[EDIT]
Zitat:
PS: *** Das Programmverzeichnis ist nach fertigsttellung deines Programmes und nach dessen Istallation C:\Programme. Und da hat kein User Zugriff darauf (seit WinXP(?)). Und deshalb wird dannzumal jeder VCersuch, da in eine Ini-Datei oder sonstwas zu schreiben, fehlschlagen.
Eine Mögliche Lösung findest du zum Beispiel hier
Das mag oft so sein...aber nicht in diesem Projekt Die Setup Routine ist für User ohne Installationsrechte und speichert deshalb in den AppData=>Local Folder auf den fast alles und jeder Rechte hat! Dieses System verwende ich bereits, weltweit bei tausenden Usern. Ohne Probleme...
Miniaturansicht angehängter Grafiken
unbenannt.png  

Geändert von gabneo ( 2. Aug 2016 um 14:46 Uhr)
  Mit Zitat antworten Zitat
Delbor

Registriert seit: 8. Okt 2006
Ort: St.Gallen/Schweiz
1.186 Beiträge
 
Delphi 11 Alexandria
 
#5

AW: TFilestream in Schleife funktioniert nur einmalig

  Alt 2. Aug 2016, 15:10
Hi gabneo

Lass den Speichermanager doch mal allfällige Speicherlecks anzeigen.
Zitat:
fhttp.Disconnect; Ist drin um sicherzustellen das der Zugriff auf den Stream beendet wird.
Wie ich schon geschrieben habe, wäre es interesant, zu wissen, was vor der Schleife passiert. Es scheint so, als müsse in der Schleife auf Objekte zugegriffen werden, die es plötzlich nicht mehr gibt.

Gruss
Delbor
Roger
Man muss und kann nicht alles wissen - man muss nur wissen, wo es steht.
Frei nach Albert Einstein
http://roase.ch
  Mit Zitat antworten Zitat
gabneo

Registriert seit: 15. Okt 2006
Ort: Deutsche Toskana :)
93 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#6

AW: TFilestream in Schleife funktioniert nur einmalig

  Alt 2. Aug 2016, 15:26
Reportmemoryleaks ist gecheckt und es gibt keine Lecks.
Dasselbe Problem taucht auch auf wenn man mit idHTTP auf einer Form einen Responsestream über .Post mit angibt.

Hier ist die Unit...

Delphi-Quellcode:
unit httpThread;

interface

uses
  Classes, SysUtils, Dialogs, Forms, Controls, ShellAPI, Windows,
  IdComponent, IdTCPConnection, IdTCPClient, IdHTTP, IdURI, IdCookieManager,
  IdIOHandler, IdIOHandlerSocket, IdIOHandlerStack, IdSSL, IdSSLOpenSSL, IdCoder,
  xmldom, XMLIntf, msxmldom, XMLDoc;

type
  http = class(TThread)
  private
    { Private-Deklarationen }
    fhttp: TIdHttp;
    fUser, fPass, fHardwarekennung, fURL, fcfg, fsrc, fsalt: string;
  protected
    procedure Execute; override;
  public
    constructor Create(User, Pass, Hardwarekennung, URL, cfg, src, salt:widestring);
  end;

implementation

uses main, downloadForm, languageStrings, passwordForm, functions, debug;

constructor http.Create(User, Pass, Hardwarekennung, URL, cfg, src, salt:widestring);
begin
  inherited Create(False);
  FreeOnTerminate := true;
  fUser := User;
  fPass := Pass;
  fHardwarekennung := Hardwarekennung;
  fURL := url;
  fcfg := cfg;
  fsrc := src;
  fsalt := salt;
  Self.Execute;
end;

procedure http.Execute;
var s,sFilename,pfad,s1:string; nlist,flist:iXMLNodeList; cfgdata: tstringlist; PHPXML: IXMLDOCUMENT; sFile: TStream; fparams, currentList:tstringlist; i:integer; Handle1:THandle; fileStream:THandleStream;
begin
  phpxml := NewXMLDocument;
  fhttp := TIdHTTP.Create(nil);
  try
    fhttp.HandleRedirects := True;
    fhttp.AllowCookies := True;
    fhttp.ReadTimeout := 15000; //Sonst Timeouts auf > Windows 8 BSystemen
    fhttp.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(fhttp);

    fparams:=tstringlist.Create;
    fparams.Add('RPC=login');
    fparams.Add('username='+fUser);
    fparams.Add('password='+fPass);
    fparams.Add('hardware='+fHardwarekennung);
    s := fhttp.Post(TIdURI.URLEncode(fURL), fparams);

    try PHPXML.LoadFromXML(s); phpxml.Active := true; except end;

    if not PHPXML.IsEmptyDoc then
    begin
      if (phpxml.DocumentElement.HasChildNodes) then
        begin
          nlist := phpxml.DocumentElement.ChildNodes;
          if (nlist.FindNode('problem') <> nil) then
          begin
            if (((nlist.FindNode('blocked') <> nil)) and (nlist.FindNode('blocked').Text>'0000-00-00 00:00:00')) or (((nlist.FindNode('removed') <> nil)) and (nlist.FindNode('removed').Text>'0000-00-00 00:00:00')) then begin try DeleteFile(PChar(fcfg)); except end; Application.Terminate; end;
             Queue( procedure begin showmessage(language.Label1.Caption) end ); //'Username or password not valid. Please check your input.'
            exit;
          end;
          //setIniFile;

          //Neues Password TODO
          //if (((nlist.FindNode('newpassword') <> nil)) and (nlist.FindNode('newpassword').Text='1')) then Form12.ShowModal;

          //XML Verschlüsseln und Speichern
          try DeleteFile(PChar(fcfg)) except end;
          try Queue( procedure begin Form1.xml.LoadFromXML(Form1.IdDecoderMIME1.DecodeString(nlist.FindNode('cfg').Text, SysUtils.TUTF8Encoding.UTF8));
              cfgdata := tstringlist.Create; try cfgdata.Text := functions.Encrypt(Form1.xml.XML.Text, fsalt + fUser + fPass + fHardwarekennung); cfgdata.SaveToFile(fcfg); finally cfgdata.Free; end; end );
          except end;

          //APPLICATION UPDATE
          //Versionscheck und ggf. Download der aktuellen Version
          if (nlist.FindNode('version') <> nil) then if (phpxml.DocumentElement.ChildNodes.FindNode('version').Text <> GetVersion) then if (MessageDlg(language.Label4.caption + phpxml.DocumentElement.ChildNodes.FindNode('version').Text + '!' + #13#10 + language.label5.caption, mtConfirmation, mbYesNo, 0) = mrYes) then
          begin
            //download.Show;
            sFilename := extractfilepath(paramstr(0)) + 'update.exe';
            try deletefile(PChar(sFilename)) except; end;
            sFile := TFileStream.Create(sFilename, fmCreate);
            try
              fparams.text := 'RPC=update';
              fhttp.Post(TIdURI.URLEncode(fURL), fparams, sFile);
            finally
              sFile.Free;
            end;
            ShellExecute(handle,'open',PChar(sFilename), PChar(''),'',SW_SHOWNORMAL); ///SP- /VERYSILENT
            application.Terminate;
          end;

          //CONTENT UPDATE
          currentList := tstringlist.Create;
          try
            currentList.Sorted:=true;
            functions.FindAllFilesUnix(currentList,fsrc,'*',true,false,true,true); //Dateiliste erstellen

            pfad:=extractfilepath(paramstr(0));
            s1 := phpxml.DocumentElement.ChildNodes.FindNode('filelist').XML;

            for i := currentList.Count-1 downto 0 do
            begin
              s := copy(currentList[i], length(fsrc) + 1);
              s := copy(s, 0, pos(#255, s)-1);
              if (pos('\', s) < 1) and ((extractfileext(s) = '') or (lowercase(extractfileext(s)) = '.xml')) then continue; //APPDATEN: Übergehen - Dateien ohne Endung, Dateien mit Endung XML

              s := copy(currentList[i], length(pfad) + 1);
              s := copy(s, 0, pos(#255, s)-1);
              if (pos('>' + s + '</file>', s1) < 1) then Deletefile(PChar(s)); //löschen
            end;

            flist := phpxml.DocumentElement.ChildNodes.FindNode('filelist').ChildNodes;

            Queue ( procedure begin Form2.log('flist.count: ' + inttostr(flist.Count)); end);
            for i := flist.Count-1 downto 0 do
            begin
              if (pos(flist[i].NodeValue + #255 + flist[i].Attributes['timestamp'], currentList.Text) > 0) then continue; //Datumsvergleich
              Queue ( procedure begin Form2.log('entry ' + inttostr(i) + ': ' + flist[i].NodeValue + #255 + flist[i].Attributes['timestamp']); end);
              //Download
              sFilename := extractfilepath(paramstr(0)) + flist[i].NodeValue;
              sFile := TFileStream.Create(sFilename, fmCreate);
              //Handle1 := CreateFile(PChar(sFilename), GENERIC_WRITE, FILE_SHARE_WRITE, nil, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
              //fileStream := THandleStream.Create(Handle1);
              try
                fparams.Text := 'RPC=download';
                fparams.Add('file=' + flist[i].NodeValue);
                fhttp.Post(TIdURI.URLEncode(fURL), fparams, sFile); //sFile fileStream
              finally
                //fhttp.Disconnect;
                //fhttp.Response.Clear;
                sFile.Free;
                //fileStream.Free;
                //CloseHandle(Handle1);
                SetFileDate(sFilename, UnixToDateTime(flist[i].Attributes['timestamp']));
              end;
            end;
          finally
            currentList.Free;
          end;

        //Applikation laden
      end;
    end else Queue( procedure begin showmessage(language.Label2.Caption); {problem connecting server} {TODO Offline Modus starten}  end );
  finally
    try fparams.text := 'RPC=logout'; fhttp.Post(TIdURI.URLEncode(fURL), fparams); except end;
    fhttp.Free;
    fparams.Free;
  end;
  Self.Terminate;
end;

end.
LG
  Mit Zitat antworten Zitat
bra

Registriert seit: 20. Jan 2015
711 Beiträge
 
Delphi 10.2 Tokyo Enterprise
 
#7

AW: TFilestream in Schleife funktioniert nur einmalig

  Alt 2. Aug 2016, 16:16
Ist das unter Windows oder bei einer mobilen Plattform? Wir hatten bei uns ein Problem unter iOS/Android, dass Indy den Stream bei einem Get nicht freigibt. Gelöst haben wir das so:

Delphi-Quellcode:
    {$IFDEF AUTOREFCOUNT}
    http.Response.ContentStream := nil; // Referenz auf AStream freigeben
    {$ENDIF AUTOREFCOUNT}
Möglicherweise braucht man bei einem Post auch sowas in der Art?
  Mit Zitat antworten Zitat
gabneo

Registriert seit: 15. Okt 2006
Ort: Deutsche Toskana :)
93 Beiträge
 
Delphi 10.2 Tokyo Professional
 
#8

AW: TFilestream in Schleife funktioniert nur einmalig

  Alt 2. Aug 2016, 17:51
Hallo bra,

das war eine super Idee, ich denke das ist die Richtige Spur und habe es getestet. Aber das hat den Fehler leider auch noch nicht gelöst.

Ähnlich gibt es noch:
Delphi-Quellcode:
fhttp.Response.ContentStream.Free
fhttp.Response.Clear;
Die leider auch nichts geholfen haben. So langsam sieht es nach einem Fehler in Indy aus, oder Indy ist für Post & Downloads nicht vorgesehen. Ich sehe mich mal nach nem Umweg um.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.114 Beiträge
 
Delphi 12 Athens
 
#9

AW: TFilestream in Schleife funktioniert nur einmalig

  Alt 2. Aug 2016, 18:28
So langsam sieht es nach einem Fehler in Indy aus, oder Indy ist für Post & Downloads nicht vorgesehen.
Einige der INDY-Leute hüpfen zwar auch hier im Forum rum, aber im Notfall kann man sich auch direkt an INDY wenden.
http://www.indyproject.org/Support.DE.aspx

Der FileStream und HandleStream brauchen fast keinen Arbeitsspeicher (den Virtuellen in deiner Anwendung).
Die Daten landen zwar im WindowsFileCache, aber der wird automatisch geleert, wenn der physische Arbeitsspeicher (RAM) zur Neige geht.

Als Erstes kann man versuchen mit ReportMemoryLeaksOnShutdown (nutzt eine der wenigen Funktionen des integrierten kleinen FastMM) oder den erweiterten Funktionen des großen FastMM rauszufinden, womit der Arbeitsspeicher sich füllt.
Es gibt auch noch andere Möglichkteiten, um den Speicher zu debuggen/prüfen/auszuwwerten.
Bei Google suchendelphi memory leak
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests

Geändert von himitsu ( 2. Aug 2016 um 18:37 Uhr)
  Mit Zitat antworten Zitat
Delbor

Registriert seit: 8. Okt 2006
Ort: St.Gallen/Schweiz
1.186 Beiträge
 
Delphi 11 Alexandria
 
#10

AW: TFilestream in Schleife funktioniert nur einmalig

  Alt 2. Aug 2016, 21:03
Hi zusammen

Was mich befremdet: Der Thread erzeugt in seinem Constructor eine IdHttp-Komponente, und die ist ein Nachkomme von TIdTCP. Und die dürfte sich wohl im Hauptthread befinden.
Des weiteren arbeitet der Thread mit einem Filestream, greift also auf die Festplatte zu...

Gruss
Delbor
Roger
Man muss und kann nicht alles wissen - man muss nur wissen, wo es steht.
Frei nach Albert Einstein
http://roase.ch
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2   

Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 01:14 Uhr.
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