Verarbeitung von sehr großen Dateien

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:

Java:
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

Top Contributor
Ü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?
 
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

Top Contributor
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

Top Contributor
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

Top Contributor
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

Top Contributor
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

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

Thallius

Top Contributor
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

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

JStein52

Top Contributor
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

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

@Thallius
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

Top Contributor
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

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

@Thallius


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.

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

Gruß

Claus
 

JStein52

Top Contributor
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 ?
 
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

Top Contributor
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.
 
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:

Java:
/*
* 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.
 
Zuletzt bearbeitet von einem Moderator:

Joose

Top Contributor
Java:
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.

Java:
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

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

Code:
           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

Code:
                     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
Code:
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.
 
Zuletzt bearbeitet:

Joose

Top Contributor
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

Top Contributor
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

Top Contributor
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

Top Contributor
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.

Java:
    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.
 
Zuletzt bearbeitet von einem Moderator:

Thallius

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

JStein52

Top Contributor
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

Top Contributor
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 :))

Java:
    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.
 
Zuletzt bearbeitet:
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

Top Contributor
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:

Java:
    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.
 
Zuletzt bearbeitet:
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

Top Contributor
Wie meinst du das ? so:

Java:
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.
 
Zuletzt bearbeitet:
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:
Java:
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");
        }
    }
}
 
Zuletzt bearbeitet von einem Moderator:

JStein52

Top Contributor
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 !
 
Zuletzt bearbeitet:
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

Top Contributor
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.
 

JStein52

Top Contributor
Etwa so:

Java:
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.
 
Zuletzt bearbeitet:

JStein52

Top Contributor
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.
 
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

Top Contributor
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 ?
 
Zuletzt bearbeitet:
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

Top Contributor
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.

Java:
    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

Top Contributor
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:

Java:
    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;
    }
 
Zuletzt bearbeitet:
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

Top Contributor
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.
 
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

Top Contributor
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 ??
 
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.
 
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.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
berserkerdq2 Findet eine parallele Verarbeitung in Java bei Threads erst statt, wenn man die Methoden auch synchronized? Und wie sieht bei Conditions aus? Java Basics - Anfänger-Themen 8
A Java, verarbeitung eines xml-files Java Basics - Anfänger-Themen 2
O Knoten und Liste verarbeitung Java Basics - Anfänger-Themen 20
P Variablen Abfangen von eingaben per java.util.Scanner und weiter Verarbeitung Java Basics - Anfänger-Themen 7
M Zeitgemäße Verarbeitung von Datumswerten in Java Java Basics - Anfänger-Themen 1
Z Objekte in der Verarbeitung stoppen Java Basics - Anfänger-Themen 2
S Arrays - Fehler bei der Verarbeitung: For input string: "Berlin" Java Basics - Anfänger-Themen 14
C Wie am besten die Verarbeitung der Eingabe verzögern ? Java Basics - Anfänger-Themen 5
G Frage zur Verarbeitung einer JSP Java Basics - Anfänger-Themen 4
G via Reflections art der verarbeitung der parameter prüfen Java Basics - Anfänger-Themen 11
H Verarbeitung von Zeichenketten Java Basics - Anfänger-Themen 8
D Problem mit der Verarbeitung eines ActionEvents Java Basics - Anfänger-Themen 7
S Bitweise Verarbeitung? Java Basics - Anfänger-Themen 7
8 Hilfe bei Trennung von GUI und Verarbeitung Java Basics - Anfänger-Themen 12
S Verarbeitung 2er KeyEvents gleichzeitig Java Basics - Anfänger-Themen 2
D BigDecimal Ausgabe sehr lang. Java Basics - Anfänger-Themen 2
X Sehr schnelle agile Entwicklung Java Basics - Anfänger-Themen 1
M (Sehr großes Problem) Listen als static in anderen Klassen verwendet Java Basics - Anfänger-Themen 12
P Erste Schritte Console - Sehr komische Ausgabe! Java Basics - Anfänger-Themen 3
B sehr lange Srings in File schreiben Java Basics - Anfänger-Themen 4
Z Sehr simpler Taschenrechner - Hilfe! Java Basics - Anfänger-Themen 10
M Suche Hilfe bei sehr kleinen Quelltexten Java Basics - Anfänger-Themen 2
M Welche externen Bibliotheken sind in Java sehr zu empfehlen? Java Basics - Anfänger-Themen 4
C Einlesen in Array von Textdatei sehr langsam Java Basics - Anfänger-Themen 7
M sehr großes Byte Array Java Basics - Anfänger-Themen 3
R OutOfmemory Exception bei sehr großer Liste (Tomcat Webservice) Java Basics - Anfänger-Themen 4
H Sehr einfache Java-Programme Java Basics - Anfänger-Themen 24
Luk10 OOP Sehr allgemeine Schnittstelle Java Basics - Anfänger-Themen 19
S Input/Output Sehr langen String in Datei schreiben Java Basics - Anfänger-Themen 8
R ArrayList sehr viel schneller als Array? Java Basics - Anfänger-Themen 2
R Sehr einfache möglichkeit ArrayList oder Array zu initialisieren? Java Basics - Anfänger-Themen 8
R Sehr kleine doubles nicht in Exponentialdarstellung ausgeben Java Basics - Anfänger-Themen 3
B ABspeichern eines sehr grossen negativen Werts Java Basics - Anfänger-Themen 6
Beckenbauer Eine anstehende (sehr simple) Applikation in UML darstellen (Klassendiagramm) Java Basics - Anfänger-Themen 20
N Name zu sehr ähnlich??? Java Basics - Anfänger-Themen 12
E Reguläre Ausdrücke mit sehr variablen Eigenschaften Java Basics - Anfänger-Themen 2
T Generic vom Generic: Zu sehr verschachtelt? Java Basics - Anfänger-Themen 6
Antoras Datei laden mit BufferedReader sehr langsam Java Basics - Anfänger-Themen 7
F Programm sehr langsam. Windows 7? Java Basics - Anfänger-Themen 23
S Eclipse .metadata ordner ist sehr gross! Java Basics - Anfänger-Themen 1
G Socket erstellen dauert sehr lange. Java Basics - Anfänger-Themen 4
D Sehr großer String lässt sich nicht bearbeiten Java Basics - Anfänger-Themen 7
G Verzeichnis auslesen mit sehr sehr vielen Bildern Java Basics - Anfänger-Themen 6
E Methode sehr langsam und funktioniert teilweise nicht Java Basics - Anfänger-Themen 3
S JFileChooser öffnet Unterverzeichnisse sehr langsam Java Basics - Anfänger-Themen 2
G Sehr eigenartige Datumsprobleme. Java Basics - Anfänger-Themen 2
I Schulprojekt !sehr wichtig! Java Basics - Anfänger-Themen 6
M sehr weit verschachtelte XML-datei mit jdom auslesen Java Basics - Anfänger-Themen 4
G g.drawLine arbeitet sehr ungenau. Java Basics - Anfänger-Themen 4
G sehr kleine Dezimalzahlen (BigDecimal) falsch angezeigt Java Basics - Anfänger-Themen 5
T Erste Schritte (SEHR mühsam); Grafiktest Java Basics - Anfänger-Themen 5
F Java Applikation ProjectX startet sehr langsam Java Basics - Anfänger-Themen 3
C FileInputStream sehr langsam Java Basics - Anfänger-Themen 5
ixChronos Letzten 4 Ziffern einer großen Zahl ausgeben Java Basics - Anfänger-Themen 3
F Java Programm, das kleine Buchstaben in einem String zählen soll und bei großen Buchstaben oder Sonderzeichen abbrechen soll. Java Basics - Anfänger-Themen 5
H Methoden in großen Klassen gruppieren oder auslagern? Java Basics - Anfänger-Themen 10
kilopack15 Rechnen mit großen Zahlen Java Basics - Anfänger-Themen 6
P Variablen Negatives Ergebnis bei Multiplikation von großen Zahlen Java Basics - Anfänger-Themen 2
J Umgang mit großen Datenmengen Java Basics - Anfänger-Themen 9
S Multiplikation von großen Zahlen, ohne BigInt uä Java Basics - Anfänger-Themen 7
J Effizienter Umgang mit großen Dateien Java Basics - Anfänger-Themen 7
C Problem mit Lesen und Speichern und Verarbeiten von großen Text Dateien Java Basics - Anfänger-Themen 5
MilchToast Teilstrings aus unbekannt großen Textdateien extrahieren. Java Basics - Anfänger-Themen 5
I Kann nicht compilieren warum? Bei großen Quellcode. Java Basics - Anfänger-Themen 8
G ArrayList bei großen Zahlen langsam? Java Basics - Anfänger-Themen 10
F Teilen einer großen Grafik Java Basics - Anfänger-Themen 2

Ähnliche Java Themen

Neue Themen


Oben