Wachsende log-Datei einlesen

Hallo,
also zunächst mal zum Ton, der ja beim Schreiben schnell falsch vorausgesetzt wird. Ich bin ganz ruhig, habe keinen Meckerton am Leib und "rede" ganz ruhig. ... nur mal zur Erklärung.
Kommen wir auf die Handwerker, bzw. zu dem Beispiel.
Was den Elektriker oder Fliesenleger angeht, ihr habt angenommen, ich gehe zu denen in den Laden, ok, da habe ich mich nicht klar genug ausgedrückt. Ich rede von rein Privat! -Wobei bei mir auf dem Lande bekomme ich auch im Laden eine erschöpfende Antwort.
Also um den Vergleich nochmal zu bemühen -in einem Heimwerkerforum gefragt:
Ich fliese ein Bad, das bekomme ich mit Geduld und Halbwissen hin. Dann habe ich ein Problem, z.B. wie bekomme ich ein Loch in die Fliese. Die Heimwerker sowie auch die Profis in diesem Forum würden schreiben: Nimm dieses Werkzeug, drücke nicht zu stark, achte sonst noch auf dies oder das. Keiner würde erwarten, das der Heimwerker jetzt das Fliesenlegen lernen will (3 Jahre Ausbildung machen z.B.) Man würde ihm auch nicht beibringen wollen, aus was für Schichten eine Fliese besteht, oder sonstiges Hintergrundwissen.
Das müss er für sein Problem nicht wissen. Und es würde auch niemand verlangen, dass er sich die Antwort selber erarbeitet, oder fragen, ob er erwartet, das die ihm vielleicht noch das Bad fliesen sollen.
Bei den Programmierern wird es aber genau so gemacht. Ich will nicht, das irgendwer mein Programm schreib, das ist nicht nötig, denn das Programm ist fertig, bis auf ein Problem.
Mit Pseudocode meinte ich die Antwort von "Improof". Warum? Warum dieses Vorführen? Die Finger waren doch eh auf der Tastatur, warum dann nicht so tippen, wie es richtig ist. ICH mache das so. Wenn mich einer z.B. zu einem Excel-Problem etwas fragt, dann antworte ich so genau, das der Fragende möglichst keine Nachfragen mehr braucht. Wenn das der Fall ist, dann habe ich das Gefühl einen "guten Job" gemacht zu haben. Meine Antwort bezieht sich auf sein Problem, wenn er es lernen will, soll er anders Fragen oder eben dann nachfragen oder sich eben mit dem Hintergrund beschäftigen. Es steht aber mir doch nicht zu, ihn zu bevormunden!!!!
Versteht ihr was ich meine?
Natürlich bin ich als fragender dankbar für die Hilfe die ich bekomme und die Zeit die andere mit meinem Problem verbringen, aber wenn die Antwort die Frage gleich beantwortet, dann spart das doch Zeit, auf beiden Seiten.
@sheel Das Dein Code 1:1 kopierbar ist habe ich gar nicht erkannt, sondern es für ein allgemeines Beispiel gehalten. Was in dem Link gemacht wird, verstehe ich nicht.
@Improof Vielen Dank für Deine Nachfrage und weiterm Interesse an meinem Problem.
Ich habe nochmal genau getestet.
Der zweite Thread wird aufgerufen, eine Schleife, die mir eine Zahl pro Sekunde ausgibt wird abgearbeitet, aber solange diese Schleife nicht beendet ist, ist das Programm nicht bedienbar.
Danach kann ich das Programm dann bedienen.
Ich verstehe das Problem jetzt so, das der Zweite Thread nicht parallel läuft. Beim Ändern bzw. Einfügen von "Sheels" code hatte ich dann Fehlermeldungen wegen der Klammersetzung, so wie es jetzt ist, ist es nicht mehr original.
Würde ich das Einlesen der Zeilen aus dem Logfile auch mit einem "Sleep" realisieren?
Was braucht ihr noch für Infos?
Java:
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.widgets.Display;


public class RunLogThread implements Runnable {
   private StyledText Textfeld;

   public RunLogThread(StyledText prozessstream) {
     Textfeld = prozessstream;
//   }                ---------------Diese Klammer sollte ich laut Fehlermeldung entfernen

   Display.getDefault().asyncExec(new Runnable(){
     public void run(){
       Textfeld.insert("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! Test: \n");
       for (int a=0; a<10; a++){
         System.out.println(a);
         try {
           Thread.sleep(500);
         } catch (InterruptedException e) {
           e.printStackTrace();
         }
       }
     }
     });
   }

   public void run() {
     System.out.println("Run im extra Thread");                   //---- wird nie ausgeführt
   }
}
 
Nur nochmal als kurzer Nachtrag, bevor ich mich dem eigentlichen Problem widme (was ja auch der Grund hier etwas zu posten sein soll):
Was den Elektriker oder Fliesenleger angeht, ihr habt angenommen, ich gehe zu denen in den Laden, ok, da habe ich mich nicht klar genug ausgedrückt. Ich rede von rein Privat!
Kommt immer darauf an, auch privat kann und wird der ein oder andere mal was dafür verlangen, wenn tatsächlich Hand angelegt werden muss, weil z.B. Erklärungen nicht mehr reichen. Zumindest meinte ich das in meinem Beitrag vorhin.

Man würde ihm auch nicht beibringen wollen, aus was für Schichten eine Fliese besteht, oder sonstiges Hintergrundwissen.
Das müss er für sein Problem nicht wissen.
Diese Aussage ist leider auch mit Vorsicht zu genießen: Was @sheel mit dem Link erreichen wollte war folgendes:
Wir wussten zu dem Zeitpunkt noch nicht, wie genau dein Code aussieht und wo das Problem liegt, dass im Textfeld nichts angezeigt wird. Ein Anfängerfehler, der aber zu 100% jedem passiert, der das erste Mal in Java und Swing o.ä. Oberflächen programmiert, ist nun jedoch der, dass man den Hintergrundthread nicht arbeiten lässt und somit (obwohl im Code alles passt) keine Ergebnisse auf der Oberfläche sieht.
Mir ist das mal bei einer ProgressBar passiert: Ich habe den Fortschritt in Prozent ausgerechnet und wollte ihn darstellen, rechnerisch alles perfekt aber eben kein Ergebnis auf dem Bildschirm.

Klar, wenn du ein Loch in eine Fliese bohren willst, dann musst du nur wissen, welches Werkzeug und nicht zu fest usw.
Dieses kleine Hintergrundwissen ist aber essentiell!
Auf dein Problem bezogen: Du musst den sog. EventDispatcher-Thread (das Werkzeug) aufrufen mit einer der von @sheel genannten Methoden (die Ausführung, "nicht zu fest").
Was der Thread genau alles macht oder sogar wie das auf dem Prozessor abläuft (die Schichten der Fliese), da gebe ich dir völlig Recht, das ist egal!


Jetzt aber genug um den heißen Brei herum geredet, den Methodenaufruf hast du ja auch schon drin.
Also mal zu deinem Problem:
Du hast den ausführenden Code in den Constructor gepackt, das ist so nicht gut. Ich hab selber mit SWT noch nicht so viel gemacht, aber ist ja eigentlich auch nicht so viel anders, wie z.B. Swing als Oberflächen-Framework zu verwenden und darin hab ich Erfahrung.

Du möchtest ja in dem unteren run(), das ja nie ausgeführt wird (bisher), den Code packen, der die Textzeile aktualisiert.
D.h. dein ganzes asyncExec()-Gebilde muss da rein und nicht in den Constructor!

Versuchs erstmal damit:
Java:
public class RunLogThread implements Runnable {
   private StyledText Textfeld;
   public RunLogThread(StyledText prozessstream) {
     Textfeld = prozessstream;
   }
   public void run() {
     while (true) {
         // Hier die Dateigröße ermitteln und mit gespeichertem Wert aus letztem Lauf vergleichen
         // Wenn sich die Größe verändert hat, dann:
         // Datei öffnen -> zur alten Position springen -> Lesen bis zum Schluss -> neue Größe und Position merken -> neuen Text anzeigen
         // Die Variablen für Größe und Position müssen als Klassenvariablen definiert werden (wie "Textfeld")
      
         Display.getDefault().asyncExec(new Runnable() {
           public void run(){
             Textfeld.insert(""); // <- Hier neuen Text einfügen
             // Hier drin nichts machen anderes machen, solange der Code hier drin ausgeführt wird, ist die GUI "eingefroren"
           }
         });
        
         // Hier den sleep einbauen (z.B. 100ms)
      }
   }
}

Erklärung:
Wenn ein Thread startet, wird das Runnable des Threads ausgeführt, genauer gesagt, die run()-Methode des Runnables. Ist diese Methode vollständig durchgelaufen, beendet sich der Thread. Das möchtest du aber ja nicht! Darum das while (true) -> Da die Bedingung immer wahr ist, hast du hier eine Endlosschleife, damit der Thread immer fröhlich weiter läuft. Möchtest du das nicht, musst du einen Start-Stop-Mechanismus programmieren, mehr dazu, falls du die Anforderung dazu hast.

Warum wird die run()-Methode bisher nicht ausgeführt? Vermutlich, weil du den Thread außerhalb nie mit start() startest!

Innerhalb des Runnabels, dass du asyncExec() übergibst, darfst du (wie beschrieben) keine Verzögerung usw. einbauen, weil die Oberfläche in dieser Zeit eingefroren ist. Danach werden allerdings alle neuen Werte auch wirklich angezeigt, darum ist das notwendig, da du sonst evtl (wie beschrieben) keine Ergebnisse, trotz eigentlich komplett richtigem Code, erhalten würdest.

Noch ein kleiner Hinweis zu Threads mit Endlosschleifen: Bitte immer ein Thread.sleep einbauen. Lässt du diese mit fullspeed durchlaufen, dann wird der Prozessor voll ausgelastet und dann geht erstmal nichts anderes mehr...hier spricht die Erfahrung aus mir ;)

Gruß
Daniel
 
Wow !!!
Alleine wäre ich nie über ein "dann müßte das so funktionieren" und andere Vermutungen hinausgekommen, verstanden hätte ich aber wohl gar nichts.
Was Du jetzt geliefert hast ist Lehrbuchqualität, echt klasse.
Vielen Dank !!!!!
Gruß Jörg
 
Zuletzt bearbeitet:
Zurück