# Verarbeitung von sehr großen Dateien



## christian_e28 (13. Okt 2015)

Hallo,
ich habe eine dat.-Datei die mehrere GB groß ist und über ungefähr 10000 Spalten und Zeilen verfügt. Dabei besteht die Datei aus einer Datumsspalte, einer Zeitspalte und den Messwerten.

Beispiel:
1951-01-01    00:00    1.0    2.0    3.0    2.0    1.0    4.0
1951-01-02    00:00    5.0    4.0    3.0    4.0    0.0    1.0  

Ich habe die Daten bereits wie folgt eingelesen:


```
package Daten;

import java.io.*;
import java.util.*;

public class Import {

    public static void main(String[] args) throws IOException {
        FileReader fr = new FileReader("pr.dat");
        BufferedReader br = new BufferedReader(fr);

        String zeile;
        while ((zeile = br.readLine()) != null) {
           if (zeile.length() == 0 || !Character.isDigit(zeile.charAt(0))) {
                    continue;
                }
                if (zeile == null) {
                    System.out.println("Keine Daten!");
                    return;
                }
            }
       br.close();
    }
}
```

Wie kann ich die Messwerte im nächsten Schritt zu Monatsmittel zusammenfassen? Hab es bei einer kleinen Anzahl an Spalten immer über einzelne ArrayListen gemacht aber was mach ich bei dieser großen und unbekannten Anzahl an Spalten? Bin für jede Idee und Anregung dankbar.


----------



## Joose (13. Okt 2015)

Überlege dir eine (logische) Struktur (-> Klasse) um eine einzelne Datenzeile aus deinem File abzubilden.
Damit kannst du schon mal jede Zeile in ein Objekt umwandeln mit dem sich leichter arbeiten lässt. Für das Monatsmittel musst du dann nur noch alle Datenzeilen für Monat X in Objekte umwandeln und diese zusammenfassen (-> eine andere Struktur/Klasse)

Wie ist denn dein Ansatz bei einer kleinen bzw. bekannten Anzahl an Spalten? Wo liegt das Problem bei mehr Spalten bzw. einer unbekannten Anzahl?


----------



## christian_e28 (13. Okt 2015)

Hab das mit den Messwerten ein bisschen falsch formuliert. Also die einzelnen Messwerte pro Tag sind unterschiedliche Stationen also es sollen immer nur die Messwerte in einer Spalte zu einem Monatsmittel zusammengefasst werden. Ich habe bisher jede Spalte in einer extra ArrayList gespeichert.


----------



## Joose (13. Okt 2015)

Egal .. die Daten einer Zeile bilden ein Objekt das du parsen solltest.
Wenn du alle Objekte für Zeitraum X hast kannst du für die gewollten Stationen die Monatsmittel berechnen.


----------



## JStein52 (13. Okt 2015)

Du kannst doch die Riesendatei zeilenweise einlesen, beim Einlesen prüfen ob das Datum passt und dann für jede Spalte den Mittelwert bilden. Dazu brauchst du immer nur eine Zeile der Datei im Speicher. Es sei denn du brauchst die Daten noch für was anderes ...


----------



## stg (13. Okt 2015)

JStein52 hat gesagt.:


> Du kannst doch die Riesendatei zeilenweise einlesen, beim Einlesen prüfen ob das Datum passt und dann für jede Spalte den Mittelwert bilden. Dazu brauchst du immer nur eine Zeile der Datei im Speicher. Es sei denn du brauchst die Daten noch für was anderes ...



Er will aber spaltenweise mitteln, nicht zeilenweise.


----------



## JStein52 (13. Okt 2015)

Ja klar, aber er kann doch beim Einlesen jede interessierende Spalte aufaddieren und am Ende durch die Anzahl dividieren, deshalb braucht er doch nicht alles im Speicher.


----------



## stg (13. Okt 2015)

Ja, du hast Recht, hab mich in deinem letzten Post verlesen. 
Ich denke, wir haben den selben Ansatz im Kopf...


----------



## Thallius (13. Okt 2015)

Ich würde die Daten in eine sauber normalisierte Datenbank packen und könnte dann mit einem query alles Abfragen was mich irgendwie interessiert ohne irgendein Rad neu erfinden zu müssen.

Gruß

Claus


----------



## JStein52 (13. Okt 2015)

Ja genau. Erste Zeile einlesen, analysieren wieviel Spalten es sind, entsprechendes Array anlegen, und dann einfach einlesen, aufaddieren, Mittelwert bilden.


----------



## JStein52 (13. Okt 2015)

Hallo Claus, er weiss aber nicht wieviel Spalten er hat. Sonst hätte ich das auch so gemacht. Und einlesen muss er die Datei auf jeden Fall, also ist es doch kein Problem 10 Spalten auzuaddieren .


----------



## stg (13. Okt 2015)

Das ist doch egal. Das ist ja das tolle an relationalen Datenbanken :O

@Thallius 


Thallius hat gesagt.:


> Ich würde die Daten in eine sauber normalisierte Datenbank packen und könnte dann mit einem query alles Abfragen was mich irgendwie interessiert ohne irgendein Rad neu erfinden zu müssen.



Vom ersten Gedanken her natürlich richtig, aber es wird schon seinen Grund haben, wieso die Daten nichtan der gewünschten Stelle in der gewünschten Form vorliegen, denke ich mir einfach mal.
Und wenn man tatsächlich nur an den konsolidierten Daten interessiert ist und den Rest hinterher eh wegschmeißt, dann muss man sich ja nicht seine eigene Umgebung so zumüllen.


----------



## Thallius (13. Okt 2015)

JStein52 hat gesagt.:


> Hallo Claus, er weiss aber nicht wieviel Spalten er hat. Sonst hätte ich das auch so gemacht. Und einlesen muss er die Datei auf jeden Fall, also ist es doch kein Problem 10 Spalten auzuaddieren .



Genau deshalb ist eine DB die bessere Wahl. Ist doch egal wieviele Spalten er hat wenn er eine Tabelle hat mit den Spalten "date", "value", "column" hat

Gruß

Claus


----------



## Thallius (13. Okt 2015)

stg hat gesagt.:


> Das ist doch egal. Das ist ja das tolle an relationalen Datenbanken :O
> 
> @Thallius
> 
> ...



Wenn er wirklich nur EINMAL diese EINE Berechnung macht hast du recht aber ich glaube da nicht dran 

Gruß

Claus


----------



## JStein52 (13. Okt 2015)

mhmm ... wie meinst du das mit der Tabelle mit den Spalten "date", "value", "column" ? Was sollte denn da drin sein ? Und meinst du nicht das wäre etwas arg viel Aufwand erst die Daten von der Datei in eine DB zu schaufeln um sie dann dort wieder rauszuholen um nur ein paar Mittelwerte zu bilden ?


----------



## christian_e28 (14. Okt 2015)

Hallo, 
erstmal danke für die vielen Antworten. Ich kann es leider nicht über eine Datenbank machen, da ich mehrere dieser Dateien habe und wirklich bei jeder Datei nur die Monatsmittel berechnet werden sollen. Die erste Zeile einlesen und die Anzahl der Spalten ausgeben ist kein Problem, da die Dateien aber immer eine andere Anzahl an Spalten aufweisen müsste ich bei jeder Datei wieder neu die Spaltenanzahl zählen und die Größe des Arrays anpassen. Gibt es da vielleicht noch eine andere Möglichkeit? Des Weiteren brauche ich die Mittelwerte aller Spalten und nicht nur von einzelnen. Könnte mir vielleicht jemand noch ein Tipp zum aufaddieren in Abhängigkeit vom Datum geben. Ich bin leider noch Anfänger und es klingt sehr logisch aber an der Umsetzung hängt es leider.


----------



## JStein52 (14. Okt 2015)

Aber wo ist das Problem ? Wenn du es für eine einzelne Datei hast dann hast du es doch auch für alle. Eine passende Klasse machen, eine Methode mittelwertBilden mit dem Dateinamen und dem interessierenden Monat als Parameter und an der Stelle wo die aufgerufen wird iterierst du über alle Dateien. Und ob du jetzt eine Spalte aufaddierst oder alle ändert ja auch nix. Wenn du mal die Anzahl der Spalten für eine bestimmte Datei hast schleifst du einfach über alle Spalten und legst die jeweilige Summe in einem Array ab das so viele Elemente hat wie es Spalten gibt. Dieses Array gibst du in deiner Methode mittelwertBilden als Returnwert zurück und machst was damit. Ach ja, und in jeder Zeile guckst du halt ob es der gesuchte Monat ist, nur dann wird aufaddiert.


----------



## christian_e28 (14. Okt 2015)

Ich versteh immer noch nicht wie ich alle Inputdaten in einem Array speichern kann. Ich hab bisher immer alle Spalten in einem extra Array abgespeichert.

Hier mein altes Beispiel mit zwei Spalten:


```
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/

package Mittelwert;

import java.io.*;
import java.util.*;
/**
*
* @author Christian
*/
public class Mit {
    
    public static void main(String[] args)throws IOException {
        try {
            PrintWriter pw = new PrintWriter("monthly.dat");
            BufferedReader br = new BufferedReader(new FileReader("pr.dat"));
            for (int i = 0; i < 10; i++) {
                String line = br.readLine();
                pw.println(line);
            }

            ArrayList<String> dateArray = new ArrayList<>();
            ArrayList<String> measurementArray =new ArrayList<>();
          
           String currentLine = br.readLine();
            while (!currentLine.equals("#end")) {
                String[] pieces = currentLine.split("\\s+");

                dateArray.add(pieces[0]);
                measurementArray.add(pieces[1]);
                currentLine = br.readLine();
            }

            ArrayList<String> monthlyArray = new ArrayList<>();
            int counter = 1;
            for (int i = 0; i <= dateArray.size() - 2; i++) {
                if (counter == 1) {
                    monthlyArray.add(dateArray.get(i));
                    monthlyArray.add(measurementArray.get(i));
                    counter++;
                } else {
                    monthlyArray.set(0, "01" + dateArray.get(i).substring(2));
                    monthlyArray.set(1, String.valueOf((Double.parseDouble(monthlyArray.get(1)) + Double.parseDouble(measurementArray.get(i)))));
                  
                    if (!dateArray.get(i).substring(3).equals(dateArray.get(i + 1).substring(3))) {
                        monthlyArray.set(1, String.valueOf(Double.parseDouble(monthlyArray.get(1)) / counter));
                                             
                        pw.println(monthlyArray.get(0) + "\t" + monthlyArray.get(1));
                        monthlyArray.clear();
                        counter = 0;
                    } else {
                        if (i == dateArray.size() - 2) {
                            monthlyArray.set(1, String.valueOf((Double.parseDouble(monthlyArray.get(1)) + Double.parseDouble(measurementArray.get(i + 1)))));
                            monthlyArray.set(1, String.valueOf(Double.parseDouble(monthlyArray.get(1)) / (counter + 1)));
                            pw.println(monthlyArray.get(0) + "\t" + monthlyArray.get(1));
                        }
                    }
                    counter++;
                }
            }
            pw.println("#end");
            pw.close();
            br.close();
        } catch (FileNotFoundException ex) {
            ex.printStackTrace();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}
```

Ich hoffe ihr könnt es mir an diesem Beispiel ein bisschen näherbringen wie ich es dann für viele Spalten machen muss, ohne das ich jede Spalte in ein extra Array speicher. Sorry für die dicke Leitung aber ich bin Anfänger und versteh zwar eure Vorschläge aber ich hab keine Ahnung wie ich es genau umsetzten kann.


----------



## Joose (14. Okt 2015)

```
ArrayList<String> measurementArray =new ArrayList<>();

String currentLine = br.readLine();
while (!currentLine.equals("#end")) {
   String[] pieces = currentLine.split("\\s+");

   if(pieces[0] == gültiges Monat) { // hier überprüfen ob das Datum zum gewünschten Monat passt
     measurementArray.add(pieces[1]); // statt index 1 muss natürlich der gewünscht angegeben werden
   }
}

double measurment = 0.0;
for (int i = 0; i < measurmentArray.size(); i++) {
   measurement += Double.parseDouble(measurementArray.get(i));
}

double mittelwert = measurement / measurementArray.size();
```

Mit diesem kurzen Codestück (an deines angelehnt) ist das Berechnen des Mittelwertes für ein bestimmtes Monat und eine bestimmte Station möglich.
In der "while"-Schleife entscheidest du je nach angegeben Parametern welches Datum und welche Station beachtet wird.


```
HashMap<Integer, ArrayList<Double>> measurements = new HashMap<>();

String currentLine = br.readLine();
while (!currentLine.equals("#end")) {
   String[] pieces = currentLine.split("\\s+");

   if(pieces[0] == gültiges Monat) { // hier überprüfen ob das Datum zum gewünschten Monat passt
     for(int i = 1; i < pieces.length; i++) {
       ArrayList<Double> measurementOfStation = measurements.get(i);
       if(measurementOfStation == null) {
         measurementOfStation = new ArrayList<Double>();
         measurements.put(i, measurementOfStation);
       }
       measurementOfStation.add(Double.parseDouble(pieces[i]));
     }
   }
}

HashMap<Integer, Double> mittelwertPerStation = new HashMap<>();
for(Map.Entry<Integer, ArrayList<Double>> pair : measurements.entrySet()) {
   int stationNumber = pair.getKey();
   double mittelwert = 0.0;
   for(Double wert : pair.getValues()) {
     mittelwert += wert;
   }
   mittelwert = mittelwert / pair.getValues().size();
   mittelWertPerStation.put(stationNumber, mittelwert);
}
```

Mit diesem Code könntest du dir den Mittelwert für alle Stationen für ein bestimmtes Monat ausrechnen


----------



## JStein52 (14. Okt 2015)

Du teilst deine Eingabezeile ja schon mit split in ihre einzelnen Spalten auf, und zwar an den Stellen wo ein Blank steht.


```
String currentLine = br.readLine();
                     String[] pieces = currentLine.split("\\s+");
```
                     pieces.length ist dann die Anzahl aller Spalten und pieces[0] ist das Datum, pieces[1]  die Uhrzeit, und die restlichen pieces sind deine Werte. und nun kannst du ein Array


```
double[] values = new double[pieces.length-2] ;
```
anlegen. Und jetzt liest du in einer Schleife bis zum Ende der Datei ein, splittest immer wieder und holst dir mit

```
values[i-2] += Double.parseDouble(pieces[i]);
```
jeweils den Wert der i.ten Spalte.  Ich hoffe du verstehst das Prinzip. Und das alles lagerst du in eine neue Methode mittelwertBilden aus die das Array values return'd

Edit:  uups, Joose. Er liest aber nach wie vor seine komplette Datei erst mal ein und bildet dann den Mittelwert. Das wollte er doch gerade nicht.


----------



## Joose (14. Okt 2015)

JStein52 hat gesagt.:


> Edit:  uups, Joose. Er liest aber nach wie vor seine komplette Datei erst mal ein und bildet dann den Mittelwert. Das wollte er doch gerade nicht.



Naja mein Code macht jetzt einmal das was getan werden soll -> Mittelwert berechnen.
Natürlich kann er diesen jetzt auch so anpassen das es für ihn passt.


Wenn man davon ausgehen kann das alle Tage eines Monat direkt untereinander stehen dann muss man nicht die komplette Datei einlesen


----------



## JStein52 (14. Okt 2015)

Auch wenn sie nicht untereinander stehen.


----------



## JStein52 (14. Okt 2015)

Es ist doch total easy die Datei zeilenweise einzulesen in eine double[] values passender grösse spaltenweise aufaddieren und durch die Anzahl teilen. Da muss man doch nicht das ganz grosse Besteck dafür auspacken.


----------



## Joose (14. Okt 2015)

Klar kann man sich die 2.Schleife sparen und alles in einer machen, so hat er es mal getrennt damit er sieht wie das Einlesen passiert und dann der Mittelwert berechnet wird.
Ob er sich nun diesen Code als Basis nimmt und danach beide Schleife zusammentut bleibt ihn überlassen


----------



## JStein52 (14. Okt 2015)

Ich habe es mal so hingeschrieben, die Prüfungen auf das passende Datum habe ich mal weggelassen und vielleicht fehlt noch die ein- oder andere Plausi-Prüfung.


```
public double[] mittelwertBilden(String datei, int monat) {
        double[] values = null;
        try {
            BufferedReader br = new BufferedReader(new FileReader(datei));
            String currentLine = br.readLine();
            String[] pieces = currentLine.split("\\s+");
       
            values = new double[pieces.length-2];
            for (int i=2; i< pieces.length; i++) {
                values[i-2] += Double.parseDouble(pieces[i]);
            }
            // jetzt ist die erste Zeile eingelesen und wir wissen wieviele Spalten es gibt
            // jetzt wird der Rest eingelesen
            while (!currentLine.equals("#end")) {
                currentLine = br.readLine();
                pieces = currentLine.split("\\s+");
                for (int i=2; i< pieces.length; i++) {
                    values[i-2] += Double.parseDouble(pieces[i]);
                }
            // Jetzt sind alle Spalten aufaddiert, und zwar für alle Zeilen
           
            }
        }
        catch (FileNotFoundException ex) {
            System.out.println("File noot found");
        }
        catch (IOException ex) {
            System.out.println("File noot found");
        }
        br.close();
        return values;
```

Noch nicht getestet. Nur um das Prinzip zu verdeutlichen. und an einigen Stellen kann man es noch vereinfachen. z.B. braucht man die Schleife über die pieces nur einmal innerhalb der while-Schleife.


----------



## Thallius (15. Okt 2015)

Hat der TO irgendwo gesagt, dass jede Zeile die gleiche Anzahl Spalten hat? Wenn nein, dann klappt Deine Methode nämlich nicht.


----------



## JStein52 (15. Okt 2015)

Das stimmt aber dann hätte er ein grösseres Problem zu wissen welcher Wert nun zu welcher Station gehört.  Und davon schreibt er nichts. Die Spalten können in jeder Datei andeers sein. Aber pro Datei wohl gleich.


----------



## JStein52 (15. Okt 2015)

Noch 1-2 kleinere Verbesserungen. Was jetzt fehlt sind die Zeilen die du in deinem Code vor den eigentlichen Messwerten scheinbar einliest, dazu hast du weiter nichts geschrieben, und die Abfrage auf den passenden Monat (habe ich mal im Kommentar und per Einrückung angedeutet. Musst du dabei aber nicht das ganze Datum berücksichtigen ? Es gibt in jedem Jahr einen Januar )


```
public double[] mittelwertBilden(String datei, int monat) {
        double[] values = null;
        try {
            BufferedReader br = new BufferedReader(new FileReader(datei));
            String currentLine = br.readLine();
            String[] pieces = currentLine.split("\\s+");
       
            values = new double[pieces.length-2];

            // jetzt ist die erste Zeile eingelesen und ein double-Array mit der
            // richtigen Spaltenanzahl erzeugt. Was du mit Datum und Uhrzeit noch machen willst
            // weiss ich nicht. pieces[0] und pieces[1]

            // jetzt werden die Werte ermittelt und alle Zeilen dabei eingelesen
            int anzahlZeilen = 0;
            while (!currentLine.equals("#end")) {
                // hier muss noch die Abfrage hin ob der Monat passt (eigentlich wohl das komplette datum)
                // if (richtiger Monat)
                      for (int i=2; i< pieces.length; i++) {
                          values[i-2] += Double.parseDouble(pieces[i]);
                      }
                      anzahlZeilen++;

                // naechste Zeile lesen
                currentLine = br.readLine();
                pieces = currentLine.split("\\s+");
            }
            // Jetzt sind alle Spalten aufaddiert, und zwar für alle Zeilen
            //pw.print("Dein Datum");
            for (int i=0; i < values.length && anzahlZeilen > 0; i++) {
                values[i] /= anzahlZeilen;  // Mittelwert
                //pw.print("\t"+values[i]);
            }
            //pw.println("");
            br.close();
        }
        catch (FileNotFoundException ex) {
            System.out.println("File not found");
        }
        catch (IOException ex) {
            System.out.println("Error during read");
        }
        return values;
    }
```

Und falls du deine Ergbenisse nur wieder in eine andere Datei schreiben willst dann baust du das ein und das return entfällt dann eben.


----------



## christian_e28 (22. Okt 2015)

Hallo und danke für die große Hilfe,
ich habe das Datum jetzt als extra Array gespeichert oder ist das überflüssig?. Die Uhrzeit ist unwichtig. Dabei ist natürlich das gesamte Datum wichtig aber ich verstehe immer noch nicht wie ich die Werte für einen Monat mittel in Abhängigkeit vom Datum . Des Weiteren habe ich keine Ahnung wie ich beim speichern in einer extra Datei, in jeder Zeile, das Datum (nur Monat und Jahr) und die gemittelten Werte für jede Station speichern kann.


----------



## JStein52 (22. Okt 2015)

Ich halte das Datum dir fortlaufend abzuspeichern für überflüssig. Du wandelst dir einfach pieces[0] mit split bei den "-" in Jahr, Monat, Tag um Und vergleichst es mit den übergebenen Parametern. Etwa so:


```
public double[] mittelwertBilden(String datei, int jahr, int monat) {
        double[] values = null;
        try {
            BufferedReader br = new BufferedReader(new FileReader(datei));
            String currentLine = br.readLine();
            String[] pieces = currentLine.split("\\s+");
 
            values = new double[pieces.length-2];

            // jetzt ist die erste Zeile eingelesen und ein double-Array mit der
            // richtigen Spaltenanzahl erzeugt. Was du mit Datum und Uhrzeit noch machen willst
            // weiss ich nicht. pieces[0] und pieces[1]

            // jetzt werden die Werte ermittelt und alle Zeilen dabei eingelesen
            int anzahlZeilen = 0;
            while (!currentLine.equals("#end")) {
                // hier muss noch die Abfrage hin ob der Monat passt (eigentlich wohl das komplette datum)
                String[] datum = pieces[0].split("-");
                if (Integer.parseInt(datum[0] == jahr && Integer.parseInt(datum[1] == monat) {
                      for (int i=2; i< pieces.length; i++) {
                          values[i-2] += Double.parseDouble(pieces[i]);
                      }
                      anzahlZeilen++;
                }
                // naechste Zeile lesen
                currentLine = br.readLine();
                pieces = currentLine.split("\\s+");
            }
            // Jetzt sind alle Spalten aufaddiert, und zwar für alle Zeilen des gewuenschten Datums
            // //pw.print("Datum (Jahr-Monat) "+jahr+"-"+monat);
            for (int i=0; i < values.length && anzahlZeilen > 0; i++) {
                values[i] /= anzahlZeilen;  // Mittelwert
                //pw.print("\t"+values[i]);
            }
            //pw.println("");
            br.close();
        }
        catch (FileNotFoundException ex) {
            System.out.println("File not found");
        }
        catch (IOException ex) {
            System.out.println("Error during read");
        }
        return values;
    }
```

Und je nach dem was du mit den gemittelten Werten in values machen willst schreibst du sie in eine Datei (und davor schreibst du in jeder Zeile noch jahr und monat) wie in Kommentar angedeutet  oder du lieferst einfach so wie bei mir oben die values zurück und machst dann was damit.

Edit: Achtung noch mal korrigiert.


----------



## christian_e28 (23. Okt 2015)

Wie bzw. geht es überhaupt die int jahr, monat und tag direkt in die Main Methode zu integrieren? Die sind nicht statisch und da gibt es immer eine Fehlermeldung. Was kann ich da machen?


----------



## JStein52 (23. Okt 2015)

Wie meinst du das ? so:


```
public static void main(......) {
    int jahr, monat = 0;
    String datei = "Eingabedatei.txt"

    //  hier berechnest du dirgendwie die gewünschten Daten (jahr, monat)
    //

    MeineKlasse meinObjekt = new MeineKlasse();
    double[] mittelwerte = meinObjekt.mittelwertBilden(datei, jahr, monat);

    // und hier kannst du nun was mit den Daten machen, z.B. in eine Datei schreiben

}
```

entweder so oder du machst die mittelwertBilden auch noch static  oder du schreibst einfach den ganzen Code in die main-Methode.


----------



## christian_e28 (24. Okt 2015)

Ich hab den ganzen Code in der Main-Methode nur gibt er mir für Jahr, Monat und Tag immer 0 aus und ersetzt es nicht durch die Werte aus pieces[0]. Was mach ich da falsch?
Wie kann ich mir dann alle Mittelwerte der einzelnen Stationen und Monate berechnen lassen. In meinen Beispiel ist es nur für ein bestimmten Monat. Hier mein Code damit ihr seht was ich falsch mache:

```
package Mittelwert;

import java.io.*;

public class Mit {

    public static void main(String[] arg) throws IOException {
        double[] values = null;
        int jahr = 0;
        int monat = 0;
        int tag = 0;
        try {
            PrintWriter pw = new PrintWriter("monthly1.dat");
            BufferedReader br = new BufferedReader(new FileReader("pr2.dat"));
            for (int i = 0; i < 16; i++) {
                String line = br.readLine();
                pw.println(line);
            }
            String currentLine = br.readLine();
            String[] pieces = currentLine.split("\\s+");
            values = new double[pieces.length - 2];
            int anzahlZeilen = 0;

            while (!currentLine.equals("#end")) {
                String[] datum = pieces[0].split("-");
                if (Integer.parseInt(datum[0]) == jahr && Integer.parseInt(datum[1]) == monat
                        && Integer.parseInt(datum[2]) == tag) {
                    if (jahr < 0 && monat < 1 && monat > 12 && tag < 1 && tag > 31) {
                        System.out.print("kein gültiges Datum!");
                        if (jahr >= 1951 && monat >= 0 && monat < 2 && tag >= 0 && tag <= 31);
                        for (int i = 2; i < pieces.length; i++) {
                            values[i - 2] += Double.parseDouble(pieces[i]);
                        }
                    }
                    anzahlZeilen++;
                }
                currentLine = br.readLine();
                pieces = currentLine.split("\\s+");
            }
            pw.print(monat + "-" + jahr);
            for (int i = 0; i < values.length && anzahlZeilen > 0; i++) {
                // values[i] /= anzahlZeilen;  // Mittelwert
                pw.print("\t" + values[i]);
            }

            pw.println("\n" + "#end");
            br.close();
            pw.close();
        } catch (FileNotFoundException ex) {
            System.out.println("File not found");
        } catch (IOException ex) {
            System.out.println("Error during read");
        }
    }
}
```


----------



## JStein52 (24. Okt 2015)

du hast in jahr, monat ja auch 0 drin stehen !!!  Du musst halt durt die Werte reinschreiben die du möchtest:

jar = 2015;
monat = 5;

Und dann kriegst du alles vom Mai 2015. Und die Mittelwertbildung ist doch schon drinnen !!!
Das was du wieder in der letzten Schleife auskommentiert hast. Und deine Abfrage auf ein gültiges Datum bewirkt jetzt dass du nur dann die Werte aufaddierst wenn du ein ungültiges Datum hast. Deine Abfragen sind da ein bisschen verdreht. Und Achtung: anzahlZeilen darfst du nur dann hochzählen wenn du auch wirklich eine Zeile eingelesen hast. Sonst stimmt später dein Mittelwert nicht !


----------



## christian_e28 (24. Okt 2015)

Ich möchte aber eine Ausgabe für alle Monate in allen Jahren und nicht für ein bestimmtes Datum. Das mit dem ungültigen Datum hab ich gleich geändert. Danke


----------



## JStein52 (24. Okt 2015)

Oh, das ist neu. Ich kenne ja deinen Anwendungsfall nicht aber wieso musst du immer wieder die Mittelwerte von historischen Daten bilden ? Wenn du die einmal hast ändern sie sich doch nie mehr ??

Aber egal. Dann machst du halt um das ganze noch zwei Schleifen für Jahr und Monat. Das wird dann zwar ein Weilchen dauern bis er die Datei immer wieder durchgenudelt hat aber das ist ja hoffentlich nur einmalig.


----------



## christian_e28 (24. Okt 2015)

Was meinst du denn um das ganze? Ich weiß nicht so recht wo ich die einfügen soll.


----------



## JStein52 (24. Okt 2015)

Etwa so:


```
public class Mittelwert {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        int startjahr = 2010;
        int jahr  = 0;
        int monat = 0;
        try {
            PrintWriter pw = new PrintWriter("monthly1.dat");
            BufferedReader br = new BufferedReader(new FileReader("pr2.dat"));
            for (int i = 0; i < 16; i++) {
                String line = br.readLine();
                pw.println(line);
            }
            br.close();
            for (jahr = startjahr; jahr<=2015; jahr++)
                for (monat = 1; monat<=12; monat++) {
                    double[] mittelwerte = mittelwertBilden("pr2.dat", jahr, monat);
                    if (mittelwerte != null) {  // wurde dieser Monat gefunden ?
                       // alles in die Ausgabedatei schreiben
                       pw.print(monat + "-" + jahr);
                       for (int i = 0; i < mittelwerte.length; i++)
                           pw.print("\t" + mittelwerte[i]);
                       pw.println("\n");
                    }
                }
            pw.println("#end");
            pw.close();
        }
        catch (FileNotFoundException ex) {
            System.out.println("File not found");
        }
        catch (IOException ex) {
            System.out.println("Error during read");
        }
    }
    
    public static double[] mittelwertBilden(String datei, int jahr, int monat) {
        double[] values = null;
        try {
            BufferedReader br = new BufferedReader(new FileReader(datei));
            // 16 Zeilen ueberspringen
            for (int i = 0; i < 16; i++) {
               String line = br.readLine();
            }

            String currentLine = br.readLine();
            String[] pieces = currentLine.split("\\s+");
            values = new double[pieces.length-2];

            // jetzt ist die erste Zeile eingelesen und ein double-Array mit der
            // richtigen Spaltenanzahl erzeugt. Was du mit Datum und Uhrzeit noch machen willst
            // weiss ich nicht. pieces[0] und pieces[1]

            // jetzt werden die Werte ermittelt und alle Zeilen dabei eingelesen
            int anzahlZeilen = 0;
            while (!currentLine.equals("#end")) {
                // hier muss noch die Abfrage hin ob der Monat passt (eigentlich wohl das komplette datum)
                String[] datum = pieces[0].split("-");
                if (Integer.parseInt(datum[0]) == jahr && Integer.parseInt(datum[1]) == monat) {
                      for (int i=2; i< pieces.length; i++) {
                          values[i-2] += Double.parseDouble(pieces[i]);
                      }
                      anzahlZeilen++;
                }
                // naechste Zeile lesen
                currentLine = br.readLine();
                pieces = currentLine.split("\\s+");
            }
            // Jetzt sind alle Spalten aufaddiert, und zwar für alle Zeilen des gewuenschten Datums
            // //pw.print("Datum (Jahr-Monat) "+jahr+"-"+monat);
            for (int i=0; i < values.length && anzahlZeilen > 0; i++) {
                values[i] /= anzahlZeilen;  // Mittelwert
                //pw.print("\t"+values[i]);
            }
            //pw.println("");
            br.close();
        }
        catch (FileNotFoundException ex) {
            System.out.println("File not found");
        }
        catch (IOException ex) {
            System.out.println("Error during read");
        }
        return values;
    }
}
```

In main wird jetzt der 16-zeilige Vorspann gelesen und geschrieben, dann wird in zwei Schleifen für jedes Jahr seit dem "startjahr" und für jeden Monat die Mittelwerte gebildet , dann in die Ausgabedatei geschrieben und am Ende das "#end" hinterher. Ich habe es aber nicht getestet.


----------



## JStein52 (26. Okt 2015)

Inzwischen bin ich mal dazugekommen es zu testen. Es hat funktioniert, die Ausgabe war noch nicht so schön, habe ich verbessert. Aber das Programm an sich tut was du möchtest.


----------



## christian_e28 (26. Okt 2015)

Danke für die große Hilfe . Ich hätte nur noch kurz zwei Fragen und zwar wie kann ich das Startjahr und Endjahr aus der Datei übernehmen und zweitens wenn ich ein Monatsmittel über alle Jahre will z.b Monatsmittel Januar 2000-2010, wie kann ich das anstellen, wenn ich die Schleife für das Jahr rausnehme funktioniert es nicht. Wo hab ich da meinen Denkfehler?


----------



## JStein52 (26. Okt 2015)

zu 1.) Start- und Endejahr aus der Datei.  Du meinst aus der gleichen Eingabedatei einfach das erste und letzte Jahr das vorkommt ?  Sind die Einträge irgendwie sortiert oder wild durcheinander ? Bisher nudelt meine Lösung ja für jedes Jahr zwischen Start- und Endejahr die Datei einmal durch. Das ist natürlich extrem ungünstig und man könnte das auf einmal pro tatsächlich vorkommendem Jahr  reduzieren. Beim ersten mal sucht man alle vorkommenden Jahre und dann bildet man eine Schleife über genau diese Jahre. (Sind eigentlich die vorkommenden Jahre zwischen Startjahr und Endejahr lückenlos ? )

zu 2.) Monatsmittel.  Möchtest du da die Monatsmittel für alle jahre ? Oder nur für bestimmte Jahre ? Ich habe es noch nicht durchdacht, aber man müsste die Schleife für die Jahre etwas umbauen. Und der Methode mittelwertBilden müsste man ein Array von Jahren mitgeben können nicht nur ein einzelnes. Und die prüft dann einfach ob die Zeile die sie gerade bearbeitet eines dieser Jahre ist !

Wie ist eigentlich dein Einsatzfall für dieses Programm ? Kriegst du da immer wieder neue Eingabedateien d.h. läuft dieses Programm ständig oder geht es nur darum einmalig solche Mittelwerte aus einer Eingabedatei zu bilden ? Der Hintergrund der Frage ist: ist es mehr oder weniger egal wie lange das Programm läuft ? z.B. Einmal im Monat nachts ?


----------



## christian_e28 (26. Okt 2015)

zu 1.) Ich meine das erste und letzte Jahr aus der Eingabedatei und die Einträge sind aufsteigend sortiert und ohne Lücken. 

zu 2.) Ich möchte die Monatsmittel zu bestimmten Zeitabschnitten. z.B. habe ich Daten von 1900 bis 2000 und möchte die Monatsmittel für Januar und so. für 1980-2000.

Es sind immer neue Dateien mit einer unterschiedlichen Anzahl an Jahren und Stationen. 
Insgesamt ist die Laufzeit nicht ganz so wichtig, weil es auf einem extra Server läuft aber je schnell es geht um so besser


----------



## JStein52 (26. Okt 2015)

Ok. Zu 1.) hätte ich da schon mal eine Änderung, funktioniert auch:
ich gehe beim einlesen des Vorspanns aus 16  Zeilen in main einfach auch die restliche Datei durch und baue eine Jahresliste auf und über die wird dann iteriert.


```
public static void main(String[] args) {
        int jahr = 0;
        int monat = 0;
        List<Integer> jahresListe = new ArrayList<Integer>();
        try {
            String currentLine = "";
            PrintWriter pw = new PrintWriter("monthly1.dat");
            BufferedReader br = new BufferedReader(new FileReader("pr2.dat"));
            for (int i = 0; i < 16; i++) {
                currentLine = br.readLine();
                pw.println(currentLine);
            }
            // Liste aller in der Datei enthaltenen Jahre bestimmen
            currentLine = br.readLine();
            while (!currentLine.equals("#end")) {
                String[] pieces = currentLine.split("\\s+");
                String[] datum = pieces[0].split("-");
                jahr  = Integer.parseInt(datum[0]);
                if (!jahresListe.contains(jahr))
                    jahresListe.add(jahr);
                System.out.println(jahresListe);
                currentLine = br.readLine();
            }
            br.close();
            for ( Integer jahrInListe : jahresListe ) {
                for (monat = 1; monat <= 12; monat++) {
                    double[] mittelwerte = mittelwertBilden("pr2.dat", jahrInListe, monat);
                    if (mittelwerte != null && mittelwerte.length > 0) {
                        // alles in die Ausgabedatei schreiben
                        pw.print(monat + "-" + jahrInListe);
                        for (int i = 0; i < mittelwerte.length; i++) {
                            pw.print("\t" + mittelwerte[i]);
                        }
                        pw.println();
                    }
                }
            }
            pw.println("#end");
            pw.close();
        } catch (FileNotFoundException ex) {
            System.out.println("File not found");
        } catch (IOException ex) {
            System.out.println("Error during read");
        }
    }
```

Zu 2.) hätte ich dann die Frage wie möchtest du denn die interessierenden Intervalle angeben ?


----------



## JStein52 (26. Okt 2015)

Das waren nur Änderungen in main. die andere Methode ist noch unverändert. Wenn du so eine Mega-Eingabedatei zur Hand hast könntest du das ja schon mal laufen lassen. Würde mich interessieren ob es halbwegs vernünftig läuft.

Edit: mir ist noch eingefallen dass ich ja bzgl. Ausgabe inzwischen in der anderen Methode auch schon was geändert habe. Deshalb hier auch von dieser der aktuelle Stand:


```
public static double[] mittelwertBilden(String datei, int jahr, int monat) throws FileNotFoundException, IOException {
        double[] values = null;

        BufferedReader br = new BufferedReader(new FileReader(datei));
        // 16 Zeilen ueberspringen
        for (int i = 0; i < 16; i++) {
            String line = br.readLine();
        }

        String currentLine = br.readLine();
        String[] pieces = currentLine.split("\\s+");

        values = new double[pieces.length - 2];

        // jetzt ist die erste Zeile eingelesen und ein double-Array mit der
        // richtigen Spaltenanzahl erzeugt.
        // jetzt werden die Werte ermittelt und alle Zeilen dabei eingelesen
        int anzahlZeilen = 0;
        while (!currentLine.equals("#end")) {
            // passt jahr und monat ?
            String[] datum = pieces[0].split("-");
            if (Integer.parseInt(datum[0]) == jahr && Integer.parseInt(datum[1]) == monat) {
                for (int i = 2; i < pieces.length; i++) {
                    values[i - 2] += Double.parseDouble(pieces[i]);
                }
                anzahlZeilen++;
            }
            // naechste Zeile lesen
            currentLine = br.readLine();
            pieces = currentLine.split("\\s+");
        }
        // Jetzt sind alle Spalten aufaddiert, und zwar für alle Zeilen des gewuenschten Datums
        for (int i = 0; i < values.length && anzahlZeilen > 0; i++) {
            values[i] /= anzahlZeilen;  // Mittelwert
        }
        br.close();
        if (anzahlZeilen > 0) {
            return values;
        }
        return null;
    }
```


----------



## christian_e28 (27. Okt 2015)

Die Datei läuft gerade und es sieht bis jetzt gut aus.

zu 2.) Das Zeitintervall kann wie im ersten Programm angegeben werden:

startjahr = 1980
for(jahr = startjahr; jahr<=2001; jahr++)


----------



## JStein52 (27. Okt 2015)

Soll das dann ein neues Programm werden ?  Oder wie unterscheidet man was du jetzt gerade machen willst: - Mittelwerte pro Monat oder Mittelwerte eines Monats für mehrere Jahr ?

Auf jeden Fall würde ich die Methode mittelwertBilden so ändern dass man ihr eine Liste von Jahren übergeben kann.  List<Integer>  oder int[]  ....  Wenn diese Liste nur ein einziges Element enthält funktioniert sie so wie bisher, wenn sie mehrere Element enthält mittelt sie eben über mehrere Jahre jeweils für einen bestimmten Monat. Oder zwei Werte falls es immer ein Intervall ist und nicht eine Liste.   In der Methode mittelwertBilden prüft man dann ob das Jahr aus der aktuellen Zeile einem Jahr aus dieser Liste entspricht.  Und das Start- und Endejahr eines solchen Intervalles willst du doch sicher nicht fest im Code drinnen stehen haben ???!!! Will sagen mir ist die Logik der main-Methode in diesem Fall noch nicht klar ? Man könnte ja z.B. Aufrufparameter benutzen und das Intervall beim Aufruf angeben. Wird nichts angegeben arbeitet alles wie bisher, werden zwei Jahre angegeben dann werden diese als Intervallangabe interpretiert ?!
Und das Format der einzelnen Zeilen in der Ausgabedatei müsste ja dann auch ein bisschen anders sein.


----------



## christian_e28 (27. Okt 2015)

Das sollen zwei Programme sein. 
Wenn das mit Aufrufparametern geht ist das natürlich besser aber davon hab eich leider keine Ahnung. 
In der Ausgabedatei würde dann die 12 Monate mit den Mittelwerten der Stationen für den ausgewählten Zeitraum stehen


----------



## JStein52 (27. Okt 2015)

Also verstehe ich es richtig, du willst sagen Monatsmittel für alle Monate von 2010 bis 2013, und nicht Monatsmittel für alle Monate in den Jahren 2010, 2012, 2013 und 2015 ?? Ich bin gerade unterwegs aber wenn es so sein soll mache ich heute abend mal eine neue main. Wie lange ist das Programm denn mit einer solchen grossen Datei gelaufen ??


----------



## christian_e28 (27. Okt 2015)

Genau, es sollen die Monatsmittel von 2010 bis 2013 sein und nicht die Monatsmittel für jedes einzelne Jahr in in dem angegeben Zeitraum. Danke schon mal im voraus 
Hab es jetzt erstmal auf meinem eigenen Rechner laufen lassen und nicht auf dem Server. Da lief es jetzt die ganze Nacht.


----------



## christian_e28 (2. Nov 2015)

Hey, danke für die große Hilfe bis jetzt aber könntest du mir bei den Monatsmitteln über mehrere Jahre nochmal helfen. Ich hab es versucht aber irgendwie klappt das nicht so recht.


----------



## stg (2. Nov 2015)

Dann musst du uns schon sagen, was genau dein Problem ist...
Was hst du versucht?
Inwieweit unterscheidet sich das Verhalten von dem was du erwartest?


----------



## christian_e28 (2. Nov 2015)

Mein Problem ist eine Liste von Jahren aus den gegeben Jahren, mit einem bestimmten Zeitabschnitt, zu erstellen und in der Methode mittelwertBilden sie als Schleife so zu verwenden,dass die Methode mittelwertBilden nur dann durchgeführt wird, wenn das Jahr in der Liste enthalten ist. Es soll in der Ausgabedatei nur 12 Monate geben die die Monatsmittelwerte eines bestimmten Zeitabschnittes enthalten.
z.B. Monatsmittel Januar 2010-2013
(Gemittelt alle Januarwerte der Jahre 2010-2013)


----------



## JStein52 (3. Nov 2015)

Gelöst. Siehe PM


----------

