Dateiinhalt einlesen , verarbeiten und Ergebnis in Datei schreiben

Ironcutain

Grünschnabel
Hallo Leute,

ich bin im Rahmen meiner Mastarbeit auf ein Problem gestoßen und versuche dieses nun mit einem selbstgeschriebenen Java Programm zu lösen und hoffe, dass ihr mich dabei unterstützen könnt. Mit der Java-Programmierung hatte ich vor einigen Jahren in der Anfangsphase meines Bachelorstudiums zutun, daher sind lediglich Grundkentnisse vorhanden. Ich versuche zunächst das grundsätzliche Problem zu beschreiben. Als Ausgangszustand ist eine Datei, die als Ergebnis einer Simulation von einem Programm ausgegeben wird. In dieser Datei steht eine Menge Zeug drin, für mich ist aber nur ein bestimmter Bereich interessant. Einen Ausschnitt aus diesem Bereich sieht man hier:

Inhalt der auszuwertenden Werte in Datei "Biegebalken_Analyse.dat"
ELEMENT KNOTEN MISES


1 90 999.7
1 89 999.7
2 90 977.4
1230 1649 1.1395E+04

Der interessante Bereich ist also im Prinzip in 3 Spalten (Element, Knoten und MISES) aufgeteilt. Davon sind nur die Werte in der Spalte "Knoten" und "MISES" von Interesse.
Ich möchte nun ein Programm schreiben, dass folgendermaßen durchgeht:
1. Nehme den ersten Wert von Spalte Knoten (90)
2. Schaue ob dieser Wert in Spalte Knoten noch einmal auftaucht
--> Wenn ja: Berechne Mittelwert aus zugehörigen Werten in Spalte "MISES". Im Beispiel: (999.7+9774)/2
--> Wenn nein: Nehme den einzelnen Wert aus zugehöriger MISES Spalte
4. Schreibe das Ergebnis mit dem zugehörigen Wert aus Spalte "Knoten" in Datei "Biegebalken_Analyse.inp" an Stelle "*TEMPERATURE" in folgender Form (Reihenfolge egal):

Ergebnis in der Ausgabedatei:
*TEMPERATURE
90, 988.6
89, 999.7
1649, 1.1395E+04

Mein Problem ist, dass ich mit dem Gesamtproblem etwas überfordert bin. Das fängt damit an, wie ich dem Programm erklären soll, ab welcher Stelle er anfangen soll die Werte auszuwerten, da halt davor in der Eingabedatei viel steht und danach auch. Ich habe nun bereits angefangen ein Programm zu schreiben. Der Begriff "MISES" taucht in der Eingabedatei nur einmal auf. Daher habe ich ein Programm geschrieben, dass nach dem Begriff "MISES" sucht und mir ausgibt. Das funktioniert schon mal:


Code:
import java.io.*; 

public class FileSearch 
  { 
    public static void main(String args[]) 
    { 
        FileInputStream fstream = new FileInputStream("Biegebalken_Analyse.dat"); 
        DataInputStream in = new DataInputStream(fstream); 
        BufferedReader br = new BufferedReader(new InputStreamReader(in)); 
        String strLine; 
        int lineNum=0;
        while ((strLine = br.readLine()) != null) 
        { 
          CharSequence arg0 = "MISES";
          lineNum++;
          if (strLine.contains(arg0)) 
           { 
            System.out.println(+lineNum); 
           } 
        } 
    } 
  }

Allerdings habe ich keine Idee wie es jetzt weitergeht oder ob es so überhaupt sinnvoll ist. Irgendwie muss man dem Programm jetzt mitteilen "und ab dieser Stelle fange an auszuwerten" und ihm dann auch die Struktur beibringen "LEERZEILEN Wert1 LEERZEILEN Wert2 LEERZEILEN Wert3" und "davon arbeite nur mit Wert 2 und Wert 3". Ich erwarte hier jetzt keine direkte Gesamtlösung. Vielleicht können die Profi's hier das Problem sinnvoll aufteilen und mir "Sichworte" nennen, die zur Lösung des Teilproblems führen, damit ich das Programm sukzessive aufbauen kann.

Ich hoffe ihr könnt mir weiterhelfen.

MFG

Ironcurtain
 

HonniCilest

Erfahrenes Mitglied
Folgende Rahmenbedingungen sind für mich unklar:
Kommen nach den Werten noch andere Strukturen oder wird die Datei mit den Werten abgeschlossen?
In welcher Dimension (Anzahl der Wertezeilen) reden wir hier?
Bist du dir sicher, dass du das mit Java tun willst?
 
Zuletzt bearbeitet:

Ironcutain

Grünschnabel
Hallo HonniCilest,

nach diesen Werten kommen erstmal zwei leere Zeilen und dann:

Code:
 MAXIMUM         6.8480E+04                                                                                                
 ELEMENT                      2991                                                                                                 

 MINIMUM                  5.764                                                                                                    
 ELEMENT                        10


Vielleicht könnte man sowas machen wie "sobald zwei Leerzeilen kommen brich ab. Oder brich ab sobald das Wort MAXIMUM auftaucht.

Anzahl der Wertezeilen kann sehr stark varrieren. Das kann sicherlich schon bis 1 mio. Zeilen hochgehen oder vielleicht sogar höher.

Ja ich würde es gerne in Java schreiben, da es die einzige Sprache ist wo Grundkentnisse vorhanden sind. Ist auch kein Problem wenn die Auswertung durch den Java-Code länger dauert. Hauptsache es funktioniert.
 
Zuletzt bearbeitet:

HonniCilest

Erfahrenes Mitglied
Ja ich würde es gerne in Java schreiben. Ist auch kein Problem wenn die Auswertung durch den Java-Code länger dauert. Hauptsache es funktioniert.

Es ging mir eigentlich nicht um die Performance, ich nahm bereits an, dass dir diese nicht so wichtig ist. Ich wollte eigentlich eher auf eine gewisse Umständlichkeit hinaus, d.h. Programmieraufwand.

z.B. bietet Power-Shell Werkzeuge, indem du mit einfachen Mitteln deine Zeilen nach dem 2. Wert in diesen Zeilen gruppieren und von jeder Gruppe den Durchschnitt des 3. Wertes in dieser Zeile berechnen lassen kannst.

Gruppierung ist hier im übrigen ein gutes Stichwort.
In Java könnte man Gruppierungen z.B. mit HashMaps oder Vergleichbaren darstellen.

Sind deine Wertezeilen die einzigen mit der Struktur "Zahl Zahl Zahl"? Und nochmal die Frage: Von welchen Dimensionen (Anzahl der betroffenen Zeilen) reden wir?
 
Zuletzt bearbeitet:

Ironcutain

Grünschnabel
Es gibt auch uninteressante Bereiche in dem File die eine ähnliche Struktur haben:

Zahl Zahl Text

Ansonsten tauch exakt die gleiche Struktur sonst nirgends auf. Allerdings würde ich nicht meine Hand dafür ins Feuer legen, dass das auch immer so ist. Der interessante Bereich für mich in der Datei kommt ja daher, dass ich in der Simulation gesagt habe, gib mir später alle Werte von Mises aus. Ich kann auch noch zusätzlich sagen, gib mir neben Mises auch S1 aus und dann wäre da nochmal ein Bereich in der Datei der die gleiche Struktur aufweist. Er würde sich lediglich dadurch unterscheiden, dass dann am Anfang nicht mehr "MISES" sondern "S1" steht. Also am besten wäre man würde den Bereich durch diesen Begriff "MISES" und als Endwert "MAXIMUM" irgendwie eingrenzen.

Anzahl der betroffenen Zeilen: 1.000.000
 

HonniCilest

Erfahrenes Mitglied
1.000.000 ist natürlich schon eine Hausnummer, welche ich nicht unbedingt in den Speicher laden würde (HashMap o.Ä.). Ich bin mir nicht sicher, ob es sinnvoller wäre die gelesenen Einträge in eine Datenbank zwischenzuspeichern. Gruppierung und Durchschnitt können denke ich auch beim Abrufen (Select-Anweisung) bei einigen Anbietern mit betrachtet werden.

Zum Parsen deiner Datei würde ich zum Scanner greifen.
Dann könntest du z.B. schreiben:
Java:
scanner.next("MISES");
Anschließend so lange
Java:
scanner.nextLine();
bis zu auf eine Leerzeile stößt.
 

Ironcutain

Grünschnabel
Was meinst du mit Anbieter? Kann ich das ganze nicht Zeilenweise verarbeiten?
Ich stell mir das jetzt so vor:
1. -> Gehe in Datei "Biegebalken_Analyse.dat" Zeile i=1 und nehme Knotenwert (Spalte 2)
2. -> Schaue ob Knotenwert bereits in Datei "Ausgabedatei.inp"
2.1-> Wenn ja, setze i++ und gehe zu 1.
2.2-> Wenn nein, schaue in "Biegebalken_Analyse.dat" ob Knotenwert nochmal auftaucht
2.2.1 -> Wenn ja addiere in beiden Zeilen die MISES-Werte und gehe zu 2.2
2.2.2 -> Wenn nein bilde Mittelwert und schreibe Ergebnis in "Ausgabedatei.inp"
Setze i++ und gehe zu 1.
Und das alles bis die Anzahl der auszulesenden Zeilen erreicht und somit alle zeilen abgearbeitet wurden.

Da brauch ich doch eigentlich nichts zwischenspeichern, da ich direkt nach jeder Zeile schreibe sofern für den jeweiligen Knoten nicht bereits ein Wert gesetzt ist.

Mir ist nur unklar, wie ich dem in jeder Zeile sage nimm den Wert aus Spalte 2 und schaue ob der schon da ist....
 

Ironcutain

Grünschnabel
So ich bin meiner Meinung nach schon ziemlich weit gekommen. Ich zeige euch mal meinen bisherigen Quellcode. Ich bin mir sicher, dass in dem Code noch sehr viel Optimierungspotenzial steckt, aber wie gesagt ich bin Anfänger und froh, dass ich überhaupt so weit gekommen bin.



Code:
import java.io.*; 
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
 
public class sko { 
  static int lineNum=0;
  
    public static int durchsuchen (File datei, String wort){
        try{
          FileInputStream fstream = new FileInputStream(datei); 
          DataInputStream in = new DataInputStream(fstream); 
          BufferedReader br = new BufferedReader(new InputStreamReader(in)); 
          String strLine; 
          lineNum=0;
          while ((strLine = br.readLine()) != null) { 
            CharSequence arg0 = wort;
            lineNum++;
            if (strLine.contains(arg0)) { 
              break;
              }   
            }
          } 
      catch(Exception e){
        System.out.println("Fehler!");
        }
      return lineNum;
      }

    public static void auslesen (int anfang, int ende, File Datei_Eingabe){
      try {
		    BufferedReader in = new BufferedReader(new FileReader(Datei_Eingabe));
		    String zeile = null;
        
        //Erst ab Anfang anfangen                                                               
        for (int i=0; i<anfang;i++)
        {
          in.readLine();
        }                       
        
       //Bis Ende auslesen 
       for (int i=0;i<=ende;i++)
        {
        zeile=in.readLine();
			  String[] results=zeile.split(" * ");
        try{
          FileWriter writer = new FileWriter ("auslesen.txt", true);
          BufferedWriter buffer = new BufferedWriter(writer);
          buffer.write("\t"+results[2]+"\t"+results[3]);
          buffer.newLine();                                                       // Neue Zeile einfügen
          buffer.close();
          }
        catch(Exception e){
          System.out.println("Fehler!");
          }
        }
	   	}
	   catch (IOException e) {
	   	e.printStackTrace();
	   }
    }
      
        private static void writeSortedNumbersToFile(List<Row> rows, File file)
            throws Exception {
        PrintWriter printWriter = new PrintWriter(new FileOutputStream(file));
        for (Row row : rows) {
            printWriter.println(row);
        }
        printWriter.close();
    }
 
    private static List<Row> readRowsFrom(File file) throws Exception {
        List<Row> rows = new ArrayList<Row>();
        Scanner scanner = new Scanner(file);
        while (scanner.hasNextLine()) {
            rows.add(Row.valueOf(scanner.nextLine()));
        }
        return rows;
    }

    static class Row implements Comparable<Row> {
        String prefix;
 
        double number1;
 
        double number2;
 
 
        public int compareTo(Row otherLine) {
            return Double.compare(number1, otherLine.number1);
        }
 
        static Row valueOf(String lineString) {
            Row line = new Row();
            String[] tokens = lineString.split("\t");
            line.prefix = tokens[0];
            line.number1 = Double.parseDouble(tokens[1]);
            line.number2 = Double.parseDouble(tokens[2]);
            return line;
        }
 
        public String toString() {
            return prefix + "\t" + number1 + "\t" + number2;
        }
    }

    public static void main(String args[]) throws Exception {
        int i=0;
        int j=0;
        int k=0;
        String Datei_Eingabe_Anfang="MISES";                                      // Anfangsposition in der Eingabedatei 
        String Datei_Eingabe_Ende="THE ANALYSIS HAS BEEN COMPLETED";              // Endposition in der Eingabedatei
        //String Datei_Ausgabe_Anfang="*Step";
        File Datei_Eingabe = new File ("Biegebalken_Analyse.dat");                // Eingabedatei
        //File Datei_Ausgabe = new File ("Biegebalken_Analyse.inp");              // Ausgabedatei
        i=durchsuchen(Datei_Eingabe, Datei_Eingabe_Anfang);                       // Zeile suchen wo Datei_Eingabe_Anfang auftaucht
        i=i+2;                                                                    // In die Zeile springen wo die Werte beginnen
        j=durchsuchen(Datei_Eingabe, Datei_Eingabe_Ende);                         // Zeile suchen wo Datei_Eingabe_Ende auftaucht
        j=j-i-10;                                                                    // In die Zeile springen wo die Werte enden
        auslesen(i, j, Datei_Eingabe);                                            //Die wichtigen Zeilen in eine seperate Datei schreiben und erste Spalte löschen
        
        //sortieren
        File file = new File("auslesen.txt");
        List<Row> rows = readRowsFrom(file);
        Collections.sort(rows);
        writeSortedNumbersToFile(rows, new File("sortiert.txt"));
    } 
  }

Ich habe jetzt meine beiden Spalten in sortierter Form vor mir liegen:

1.0 999.7
2.0 999.7
2.0 977.4
3.0 977.4
3.0 902.3
4.0 902.3
4.0 775.3

Jetzt müsste ich diese Datei nochmal durchgehen und die Mittelwerte bilden, falls Knoten mehrfach auftauchen. Z.b. der Knoten 2.0

Mittelwert: (999,7+977,4)/2...


Das Ergebnis müsste ich dann in der Form:
1.0 999.7
2.0 988,6
3.0 939,9
....

in eine neue Datei schreiben. Am besten in die Ausgabedatei "Biegebalken_Analyse.inp", aber dort in einer bestimmten Zeile. Wie kann man eigentlich in eine bereits bestehende Datei wo bereits Text enthalten ist, mitten in eine bestimmte Zeile reinschreiben? Mit "true" gehts ja nur am Ende der datei, mit "false" wird der Inhalt erstmal gelöscht aber das will ich ja nicht.
Ich hoffe jemand kann mir weiterhelfen.

P.s. falls jemand Verbesserungsvorschläge für meinen bisherigen Code hat, wäre ich auch sehr dankbar.

Mfg Ironcurtain