Anwendung reagiert nicht mehr



  • Hilfe,
    und zwar habe ich mit dem Borland 5.0 CBuilder Enterprise ,eine Anwendung geschrieben. Diese Anwendung ist aber sehr sehr sehr langsam(liest ein 20MB
    in mehr als 30 Minuten aus), aber das ist nicht das Hauptproblem.
    Die Anwendung reagiert nicht mehr nach Aufruf der Auslese Funktion.
    Realisiert habe ich das mit fstream. Und das einzigst aktive ist ProgressBar.
    CPU Auslastung ist sehr minimal.

    So hat einer,wenn auch kompliziert, einen Lösungsvorschlag?

    Multithreaded oder andere Funtion zum Dateien auslesen?

    Ich weiss nicht was ,den Fehler hervorruft.
    In einer Doskonsole hatte ich dieses Problem nicht.



  • Also ich habe gestern mal Google bemüht,und kam zu den Ergebnis, das die Anwendung Multithreaded sein muss.

    Ein tolles Tutorial habe ich hier gefunden.

    Nun habe ich es so gelesen,das die Aktion, wo es aufhört zu reagieren,in einer extra Thread Klasse sein muss.

    Wenn es an dem so wäre,muss ja fstream und alles in die Klasse.

    Und man muss denn für alle grossen Funktionen Threads aufmachen.

    Bitte nicht meckern, wenn ich das ein oder andere hier verwechselt habe.

    Und was meint ihr sollte ich die Datei anders auslesen als mit fstream?



  • Diese Anwendung ist aber sehr sehr sehr langsam(liest ein 20MB
    in mehr als 30 Minuten aus), aber das ist nicht das Hauptproblem.

    Da stimmt an Deiner Funktion aber was nicht. Wir haben irgendwann mal Delphi- gegen C++-Builder-Code antreten lassen um eine 200 MB Textdatei zu lesen und zu schreiben:

    BCB6:
    Erzeugen: 1,11053416006783
    Speichern: 10,2289553560578

    BCB6:
    Laden: 8,34281228480156
    Auswerten: 5,13771219526504

    Delphi5:
    Laden: 8,09787640607954
    Auswerten: 3,51226538568449

    Die Zeiten sind jeweils in Sekunden! In Delphi wurde per fstream geladen, ich hab'S per TStringList::LoadFromFile() gemacht. Das Auswerten beschränkte sich darauf, jede Zeile in einzelne Strings mit fester Feldlänge aufzuteilen. Es wurde kein Threading verwendet. Und die BCB-Routine wurde nicht mal irgendwie optimiert...



  • Also ich habe nochmal geguckt,und finde kein Auslese Fehler.

    Ich öffne mit mit fstream eine Datei.

    Lasse in einer do-while schleife jeden Offset anspringen(seekp).

    Geht los bei 1 bis Dateiende.

    Dann soll er nur Vergleichen,ob das Zeichen identisch mit ein Zeichen was ich aus ein Char array(char name[255]="00001278|§5§|00112233|§5§|") lese ist.

    Warum das so lange dauert weiss ich nicht.

    Und ich hab keine Idee mehr woran es liegen kann.

    ]



  • Wenn Du für jedes einzulesende Zeichen seek verwendest, hast Du den Übeltäter schon gefunden...



  • Erster mal Danke für die schnelle Hilfe.

    Was ist denn jetzt dein Rat?

    Also ich muss zu jeden Offset 1x.

    Stellt die VCL eine andere Möglichkeit bereit,Datein zu öffnen(ausser LoadFromFile und co) ,und die dann Offset genau anzuspringen,und Byte für Byte auszuwerten?



  • Also ich habe jetzt alles auf ein Minimum gesetzt.

    Ich hab nur noch eine do-While Schleife mit ner posi++;
    mehr nicht.

    Trotzdem dauert das ewig.

    weiss einer noch ein Rat?



  • ja, weil Du vermutlich immer nur ein Zeichen pro Durchgang liest. Verwende mal einen Puffer und lese immer 1024 Zeichen auf einmal ein. Oder reserviere Dir gleich genügend Speicher als Puffer, um die komplette Datei in den Speicher zu laden.



  • In der Schleife ist nur noch ein aktiver Befehl : posi++;
    alles andere wurde rausgenommen, nur leider brauch der immernoch ewig.



  • zeig doch mal Deinen Code, ansonsten kann ich lange raten, wie Du es machst...



  • Soll ich jetzt 2700 Code Zeilen,und die Externen Fuktionen alle posten?



  • Natürlich nicht! Nur den relevanten Teil



  • So habe mal nen Source Code in meine anderen thread gepostet.



  • Also nun habe ich nur noch das seekp Problem.
    Nachdem die Zeile:
    big.seekp(posi);
    hinzugefügt wurde habe ich, wieder das problem,das es ewig dauert bis es zu durch gelaufen ist.



  • iFileHandle = FileOpen(OpenDialog1->FileName, fmOpenRead);
          iFileLength = FileSeek(iFileHandle,0,2);
          FileSeek(iFileHandle,0,0);
          pszBuffer = new char[iFileLength+1];
          iBytesRead = FileRead(iFileHandle, pszBuffer, iFileLength);
          FileClose(iFileHandle);
    

    Das habe ich in der borland Hilfe gefunden.

    Nun meine Frage ist es besser,alles in eins, in einen string zu speichern.
    Um dann dort alles zusuchen?

    Ist es dann vom Speed her besser,wenn man char arrays, zum vergleichen nimmt?

    Und was ist wenn man eine Datei von 2 GB oder sowas öffnet?

    Stürzt der PC dann bedingslos ab?



  • Nicht, wenn der Rechner über ausreichend Speicher verfügt (physikalischen + virtuellen). Dauern tut es trotzdem, schliesslich lesen aktuelle Festplatten grademal 20 - 50 MB pro Sekunde (Dauertransferrate), und wenn der physikalische Speicher nicht ausreicht geht das Swappen los, was natürlich komplett kontraproduktiv ist (gleichzeitig die Datei von Platte lesen und die Swapdaten auf Platte schreiben).
    Du musst halt eine sinnvolle Grösse für den Puffer festlegen.

    Und was das Seeken betrifft: bei jedem Lesen wird der Dateizeiger automatisch um die Zahl der gelesenen Bytes weitergesetzt, es ist also allenfalls zu Beginn des Lesens ein Seek an den Anfang des Puffers erforderlich.



  • Hi,

    ohne sagen zu können, ob OpenFile oder TFileStream besser geeignet ist und unter Berücksichtigung, dass ich nur praktisch keine Dateizugriffe handhaben muß, da ich normalerweise alles über DBs mache...
    Man könnte es so lösen:

    AnsiString asFileNameAndPath = "c:\\sltest.txt";
    TFileStream* myfs = NULL;
    char* myfsbuf = NULL;
    int myfsbuf_size = 1024;
    int myfsbuf_read;
    try
    {
    	try
    	{
    		myfs = new TFileStream(asFileNameAndPath, fmOpenRead);
    		myfsbuf = new char[myfsbuf_size];
    		myfs->Position = 0;
    		do
    		{
    			myfsbuf_read = myfs->Read((void*) myfsbuf, myfsbuf_size);
    			// hier Daten auswerten
    		} while (myfsbuf_read == myfsbuf_size); // sobald der Puffer nicht mehr vollständig gefüllt wird, ist die Datei zu Ende
    	}
    	catch(...)
    	{
    		ShowMessage("Fehler beim Lesen der Datei.");
    	}
    }
    __finally
    {
    	if (myfs)
    		delete myfs;
    	if (myfsbuf)
    		delete[] myfsbuf;
    }
    

    Hierbei werden die Daten immer in 1 KB großen Blöcken eingelesen (myfsbuf_size)... Wenn Du myfsbuf_size testweise mal auf 1 setzt, wirst Du feststellen, dass das Lesen bereits deutlich länger dauert.

    Ich hoffe das hilft Dir weiter. Wie Du am besten vorgehst, hängt jedoch davon ab, was mit den Daten zu geschehen hat. Aber auch wenn Du immer nur ein 1 Byte aus der Datei brauchst, würde ich die Lösung über einen Puffer bevorzugen.

    Abschließend noch mal der Hiweis: Ich habe damit keinerlei praktische Erfahrung. Wenn also jemand einen besseren Vorschlag hat...



  • So mit buffer arbeiten habe ich mir auch überlegt.

    Nur ich hab dann einn Problem,wenn jetzt die Suchwerte über ein Buffer hinausgehen, habe ich ja eine Unterbrechung. Diese Unterbrechung ruft denn ja hervor das die zu suchende Werte nicht gefunden werden.

    Also halte ich die Idee mit den Buffer,hier eher als schlechtere Wahl.
    Und Jansens Idee finde ich auch gut,nur zweifel ich dran ob ich dann mein Zeitproblem löse, weil er denn ja bei einer 2GB Datei fast nur am swappen ist.
    Und diese Suchroutine ja mehr wie wie einmal läuft(jenachdem wieviel Werte er suchen muss), kann es sein das er auch mal 100 den Prozess durchläuft.
    Und wenn dann jeder Suchdurchgang,mehrere Minuten (so ca 10Min rum),braucht
    für eine Suche.
    10*100 Minuten sind nun wirklich beim besten Willen zuviel.

    Also ich weiss nicht,keine Lösung mehr,die mir helfen könnte.

    Wenn ich nochmal ein Geistesblitz kriege,setz ich mich ran.



  • Suchen über Puffergrenzen hinweg sollte auch gehen. Ist halt nur entspechend mehr Aufwand. Ich könnte mir eine Lösung mit 2 Puffern vorstellen. Wenn Du am Ende des ersten Puffers angekommen bist 'kopierst' (am besten nur einen Zeiger) Du den zweiten Puffer in den ersten und lädst das nächste KByte in den zweiten Puffer...



  • So ich habe jetzt die ganze datei in Char Array gepackt. So wie es Jansen meinte.

    Und jetzt liest der 12Minuten wieder diese brühmten 20Mb ein.
    Was mach ich den falsch?

    Den big.seekp(ios::beg);
    habe ich nachdem Fileöffnen gesetzt.
    In der Schleife arbeite ich nur noch mit big.get(byte);

    Und ich habe nix gefunden,was fstream mit Buffer kann.
    (fstream big("test.dat",ios::in|ios::out|ios::binary);)


Anmelden zum Antworten