![]() |
Delphi-Version: XE
TFilestream in Schleife funktioniert nur einmalig
Hallo,
hat jemand eine Idee warum folgender Code in der Schleife nach einem Durchlauf hängen bleibt?
Delphi-Quellcode:
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.
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; Mit einem Handle hatte ich leider auch keinen Erfolg:
Delphi-Quellcode:
Was mache ich falsch?
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; LG |
AW: TFilestream in Schleife funktioniert nur einmalig
Was passiert denn, bzw. passiert nicht wenn Du mit [F7]/[F8] da durch steppst?
Gruß K-H |
AW: TFilestream in Schleife funktioniert nur einmalig
Hi gabneo
Delphi-Quellcode:
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.
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; 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 ![]() |
AW: TFilestream in Schleife funktioniert nur einmalig
Liste der Anhänge anzeigen (Anzahl: 1)
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.
Delphi-Quellcode:
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.Disconnect;
Delphi-Quellcode:
wieder aufbaut. 8 Stück schafft er jetzt in Reihe...bis eben der Arbeitsspeicher knapp wird
fhttp.Post(...
[EDIT] Zitat:
|
AW: TFilestream in Schleife funktioniert nur einmalig
Hi gabneo
Lass den Speichermanager doch mal allfällige Speicherlecks ![]() Zitat:
Gruss Delbor |
AW: TFilestream in Schleife funktioniert nur einmalig
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:
LG
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. |
AW: TFilestream in Schleife funktioniert nur einmalig
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:
Möglicherweise braucht man bei einem Post auch sowas in der Art?
{$IFDEF AUTOREFCOUNT}
http.Response.ContentStream := nil; // Referenz auf AStream freigeben {$ENDIF AUTOREFCOUNT} |
AW: TFilestream in Schleife funktioniert nur einmalig
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:
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.
fhttp.Response.ContentStream.Free
fhttp.Response.Clear; |
AW: TFilestream in Schleife funktioniert nur einmalig
Zitat:
![]() 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. ![]() |
AW: TFilestream in Schleife funktioniert nur einmalig
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 |
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:58 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