# Header auslesen. Problem.



## gondor (6. Feb 2005)

hallo!

ich muss aus einem header sensoren und deren einheiten herausfiltern. wie kann man das am besten machen?

hier der header:

DASYLab - V 7.00.03                                                                                      
Schaldbldname : ArcticCell3.0                                                                            
Datum : 2004-03-09
Zeit : 14:29:41                                                                                                                                                     
Kanalzahl : 8                                                                                           
Zeit ;S1-H01 [°C];S1-H01 [%rH];S1-H02 [°C];S1-H02 [%rH];S1-H03[°C];S1-H03[%rH];S1-H04[°C];S1-H04[%rH];

muss man das in einer map speichern oder was ist hier sinnvoll?

S1-H01 - °C
S1-H01 - %rH

S1-H02 - °C
S1-H02 - %rH

ich kann den header als string einlesen. wie sollte dann weiterverfahren werden? 

wäre um einen vorschlag dankbar,


----------



## foobar (6. Feb 2005)

Das lässt sich sehr einfach durch Regexe lösen.
http://java.sun.com/j2se/1.4.2/docs/api/java/util/regex/Pattern.html


----------



## gondor (6. Feb 2005)

*uff*...

wie kann das näher aussehen?

muss ich da nach etwas 'bestimmten' suchen?


----------



## foobar (6. Feb 2005)

Such mal nach Regex oder Pattern Matching


----------



## gondor (6. Feb 2005)

hey foobar!

leider habe ich keinen ansatzpunkt wie ich mit dem pattern an die richtigen sensoren und deren einheiten komme. kannst du mir evtl. noch einmal einen tipp geben? ich verwende bislang das pattern für format-überprüfungen (z.B. ip-adresse)

wie müsste der regex dazu aussehen? vielen dank :cry:


----------



## Dreezard (7. Feb 2005)

Also das kann man auch ohne Pattern lösen:

Du liest die Datei aus und prüfst ob der String miz 'Zeit' beginnt.
Danach den String mit nem StringTokenizer am ';' splitten. Dann kannst du in einer Schleife die einzelnen Teile bis zum '[' auslesen (die position erfragst du mit indexOf()). Dann den Teil in den Klammern auslesen. Das alles kannst du ja in ein array speichern, welches du in geigneter Form auslesen und verwenden kannst


----------



## foobar (7. Feb 2005)

```
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class HeaderReader
{
    public void compute(String input)
    {
        String[] lines = input.split(";");
        Pattern p      = Pattern.compile("(.*?)\\s*\\[(.*?)\\]");
        for(String s: lines)
        {
            Matcher m = p.matcher(s);
            if(m.matches())
            {
                System.out.println("Header: " + m.group(1) + " Value: " + m.group(2));
            }
        }
    }
    
    public static void main(String[] args)
    {
        String s = "Zeit [s];S1-H01 [°C];S1-H01 [%rH];S1-H02 [°C];S1-H02 [%rH];S1-H03[°C];S1-H03[%rH];S1-H04[°C];S1-H04[%rH];";
        new HeaderReader().compute(s);
    }
}
```


----------



## gondor (7. Feb 2005)

@Dreezard

hatte es so anfangs gedacht. ist natürlich die 'umständliche' version...

@foobar

ah, sieht gut aus 

bekomme aber hier

```
for(String s: lines)
```

noch einen fehler...

danke für deine mühe!


----------



## bygones (7. Feb 2005)

das ist ein Feature von Java 5 - läfut daher nur, wenn du java 5 nutzt...

ansonsten musst du nie "alte" for schleife nutzen


----------



## gondor (7. Feb 2005)

@deathbyaclown

wie ist denn die for-schleife für java 5 zu verstehen?

was meinst du genau mit 'alte'?


----------



## foobar (7. Feb 2005)

Das ist die alte For-Schleife:

```
public void compute(String input)
    {
        String[] lines = input.split(";");
        Pattern p      = Pattern.compile("(.*?)\\s*\\[(.*?)\\]");
        for(int i =0; i < lines.length; i++)
        {
            Matcher m = p.matcher(lines[i]);
            if(m.matches())
            {
                System.out.println("Header: " + m.group(1) + " Value: " + m.group(2));
            }
        }
    }
```


----------



## gondor (7. Feb 2005)

so...

```
for (int i = 0; i <= lines.length - 1; i++) {
}
```

kewl, es funktioniert  danke leute!


----------



## gondor (7. Feb 2005)

ist es eigentlich sinnvoll die werte in eine hashmap zu legen?

dort kann ich doch einem key (hier der sensor) mehrere values (einheiten) zuordnen, oder? 
muss man da eine hashtable oder eine hashmap benutzen? oder etwas ganz anderes?

S1-H01 - °C
S1-H01 - %rH

S2-H01 - °C
S2-H01 - %rH

was passiert, wenn ich den key doppelt eintragen möchte? exception?

sry, wenn ich nerve...

gondor(..)


----------



## foobar (7. Feb 2005)

Hier wird die neue For-Schleife beschrieben http://www.galileocomputing.de/artikel/gp/artikelID-152



> st es eigentlich sinnvoll die werte in eine hashmap zu legen?
> 
> dort kann ich doch einem key (hier der sensor) mehrere values (einheiten) zuordnen, oder? muss man da eine hashtable oder eine hashmap benutzen? oder etwas ganz anderes?


Eine Map speichert Key-Value Paare. Dabei wird jedem Value ein eindeutiger KEy zugewiesen.
Es kommt darauf an was du mit den Daten machen willst, so pauschal kann man nicht sagen, welche Datenstruktur am besten geeignet ist.
Wie wilst du denn später auf die Daten zugreifen?


----------



## foobar (7. Feb 2005)

> was passiert, wenn ich den key doppelt eintragen möchte? exception?


Eine Exception fliegt nicht, aber der alte Value geht verloren.
Du brauchst auf jeden fall einen eindeutigen Key. S1-H01 ist nicht eindeutig da er mehrmals vorkommt.


----------



## gondor (7. Feb 2005)

ich muss später die werte in eine db-tabelle laden, wobei ich die spaltennamen aus den namen der sensoren erzeuge. daneben brauch ich die einheit, um zu wissen, welche sensorwerte zu welcher einheit gehören...


----------



## foobar (7. Feb 2005)

Ich würde die Werte in einem Header-Objekt speichern:

```
class SensorHeader
{
   private String s1h011;
   private String s1h012;
 ...

// Getter and Setter-Methods

}
```

Falls die Werte der Header fix sind z.b. °C, könnte man diese als Konstanten oder Typesafe-Enums speichern.


----------



## gondor (7. Feb 2005)

hm... 

wie würden denn dann die getter -und setter aussehen? so?

setSensor(String name, String unit)

getSensor(String unit)

getUnit(String sensor)

wie sehe denn der String 's1h011' aus? so?

String s1h011 = "°C";

gondor(..)


----------



## foobar (7. Feb 2005)

Da ich noch ein paar Verständnisprobleme habe, kann ich dir keine adäquate Antwort liefern.

Was genau beschrieben die Header-Felder?
Warum gibt es immer 2 Felder die selben Namen tragen?
Wofür steht %rH?
Wie sehen die entsprechenden Datenfelder aus?
Auf welche Informationen willst du später in der DB zugreifen?


----------



## gondor (7. Feb 2005)

hier mal was ich vor habe:

ich habe ein file. dieses soll in eine db geladen werden. 

das file besitzt immer den gleichen header. in dem file kann die anzahl der sensoren unterschiedlich sein.

dabei handelt es sich um messungen. ein sensor kann 2 messwerte aufnehmen (temperatur + feutigkeit)

DASYLab - V 7.00.03                                                                                      
Schaldbldname : ArcticCell3.0                                                                            
Datum : 2004-03-09
Zeit : 14:29:41                                                                     
Blocklaenge : 1                                                                                          
Delta : 0.000816327 sec.                                                                                 
Kanalzahl: 8                                                                                           
Zeit ;S1-H01 [°C];S1-H01 [%rH];S1-H02 [°C];S1-H02 [%rH];S1-H03[°C];S1-H03[%rH];S1-H04[°C];S1-H04[%rH];
2004-12-12-13:00:10	1.000000	2.000000	3.000000	4.000000	5.000000	6.000000	7.000000	
2004-12-12-13:00:20	-20.000000	0.000000	-20.000000	0.000000	-20.000000	0.000000	-20.000000
2004-12-12-13:00:30	-20.000000	0.000000	-20.000000	0.000000	-20.000000	0.000000	-20.000000
...

diese sensor-werte möchte ich in mein db-schema einlesen. und genau hier liegt die schwierigkeit!!!

es existieren tabellen:

tabelle_unit(id, name)

1, °C
2, %rH
...

tabelle_sensor(id, name, id_unit)

1, S1H01, 1
2, S1H01, 2
3, S2H01, 1
...

tabelle_person(id, name)

1, Gustav Gans
2, Donald Duck
...

tabelle_versuch(id, name)

1, Versuch 1
2, Versuch 2
...

tabelle_protokoll(id, name, person_id, versuch_id)

1, Protokoll 1, 1, 1
2, Protokoll 2, 1, 1
...

tabelle_sensor_wert(id, sensor_id, protokoll_id, sensor_time, sensor_value)

1, 1, 1, 2004-12-12-13:00:10, 1.000000
2, 1, 1, 2004-12-12-13:00:20, -20.000000
...
7, 2, 1, 2004-12-12-13:00:10, 2.000000
8, 2, 1, 2004-12-12-13:00:20, -20.000000

(1, S1H01 (°C), Protokoll 1, 2004-12-12-13:00:10, 1.000000) alle °C Werte für Sensor S1H01 füllen...
...
(1, S1H01 (%rH), Protokoll 1, 2004-12-12-13:00:10, 2.000000) alle %rH Werte für Sensor S1H01 füllen...

aber wie das zu realisieren ist... da mache ich mir schon laaange kopfzerbrechen.

leider kann man mit dem mysql-befehl LOAD INFILE... nicht viel machen  

bisher kann ich eine tabelle erstellen, wo die ganzen werte gespeichert werden können:

temp_tabelle (time, S1H01, S1H01, S2H01, S2H01...)

2004-12-12-13:00:10, 1.000000, 2.000000, 3.000000, 4.000000
2004-12-12-13:00:20, -20.000000, 0.000000, -20.000000, 0.000000
...

nun muss ich die werte noch in die tabelle sensor_wert eintragen, damit mein db-schema richtig funktionieren kann.

wenn mir hier mal jemand weiterhelfen könnte, wäre ich suuuper froh!!!!


----------



## foobar (7. Feb 2005)

```
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class HeaderReader
{
    public List readHeader(String input)
    {
        List header = new Vector();
        String[] lines = input.split(";");
        Pattern p      = Pattern.compile("(.*?)\\s*\\[(.*?)\\]");
        for(int i =0; i < lines.length; i++)
        {
            Matcher m = p.matcher(lines[i]);
            if(m.matches())
            { 
                Sensor s = null;
                //System.out.println("Header: " + m.group(1) + " Value: " + m.group(2));
                if ("°C".equals(m.group(2)))
                {
                    s = new Sensor(m.group(1), Type.DEGREE);
                }
                else
                {
                    s = new Sensor(m.group(1), Type.HUMIDITY);
                }
                header.add( s );
            }
        }
        return header;
    }
    
    
    public static void main(String[] args)
    {
        String s = "Zeit [s];S1-H01 [°C];S1-H01 [%rH];S1-H02 [°C];S1-H02 [%rH];S1-H03[°C];S1-H03[%rH];S1-H04[°C];S1-H04[%rH];";
        List header =  new HeaderReader().readHeader( s );
        Iterator it = header.iterator();
        while (it.hasNext())
        {
            Sensor sensor = (Sensor)it.next();
            System.out.println("Sensor name " + sensor.getName() + " Sensor type " + sensor.getType().getId());
        }
    }
}


class Sensor
{
    private String name;
    private Type type;
    
    public Sensor(String name, Type type)
    {
        this.name = name;
        this.type = type;
    }
    
    public String getName()
    {
        return this.name;
    }
    
    public Type getType()
    {
        return this.type;
    }
}

class Type
{
    private int id;
    public static final Type DEGREE = new Type(1);
    public static final Type HUMIDITY = new Type(2);
    private Type(int id)
    {
        this.id = id;
    }
    
    public int getId()
    {
        return this.id;
    }
}
```

Aus dem Header wird jetzt eine Liste von Sensor-Objekten erstellt, dann kannst du  später, wenn du einen Datensatz einliest ganz leicht herausfinden, zu welchem Sensor/Type er gehört. Denn jede Spalte in den Datensätzen entspricht dem Index in der Liste der Sensoren. 
z.b.
Spalte 1 => headers.get(1)

liefert dir ein Sensor-Objekt zurück das du dazu verwenden kannst um die Daten später in die DB zu schreiben.

HTH


----------



## gondor (7. Feb 2005)

freut mich, dass du dir die mühe machst mir zu helfen 

werde das mal implementieren und dann schauen.

es werden bestimmt dazu noch einige fragen auftauchen, wärst du evtl. bereit mir bei meinem projekt dann wieder weiterzuhelfen?

gondor(..)


----------



## foobar (7. Feb 2005)

> es werden bestimmt dazu noch einige fragen auftauchen, wärst du evtl. bereit mir bei meinem projekt dann wieder weiterzuhelfen?


Na klar ;-)


----------



## gondor (8. Feb 2005)

so... langer tag ... nicht wirklich weitergekommen... 

hänge immer noch an der stelle fest, die werte aus der temp-tabelle in die tabelle_sensor_wert 
zu übernehmen, so dass die richtigen sensor-werte auch dem sensor zugeordnet werden können.

temp_tabelle (time, S1H01, S1H01, S2H01, S2H01...)

2004-12-12-13:00:10, 1.000000, 2.000000, 3.000000, 4.000000
2004-12-12-13:00:20, -20.000000, 0.000000, -20.000000, 0.000000
...

tabelle_sensor_wert(id, sensor_id, protokoll_id, sensor_time, sensor_value) 

Spalte 1 + Spalte 2 (messzeit und sensor 1 für °C)
1, 1, 1, 2004-12-12-13:00:10, 1.000000 
2, 1, 1, 2004-12-12-13:00:20, -20.000000

...

Spalte 1 + Spalte 3 (messzeit und sensor 1 für %rH) 
7, 2, 1, 2004-12-12-13:00:10, 2.000000 
8, 2, 1, 2004-12-12-13:00:20, 0.000000

...

Spalte 1 + Spalte 2 (messzeit und sensor 2 für °C) 
13, 3, 1, 2004-12-12-13:00:10, 2.000000 
14, 3, 1, 2004-12-12-13:00:20, 0.000000

hier mein plan:

insert into tabelle_sensor_wert value (zeit, value) select zeit, S01H01 from temp_tabelle;

aber ich brauche doch noch eine WHERE-Clausel, oder? 
um sagen zu können an welcher Stelle (also  WHERE tabelle_sensor_value.sensor.id = 'Spalte 1') 

sind meine erklärungen eigentlich 'einleuchtend'? (das frage ich mich auch ab und an mal 

brauche experten-rat. wie  komm ich hier weiter? zebrech mir schon den kopf...

gondor(..)


----------



## foobar (8. Feb 2005)

Wofür brauchst du eine temp-Tabelle?
Welche Datensätze willst du in die Tabelle sensor_wert_value einfügen?



> um sagen zu können an welcher Stelle (also WHERE tabelle_sensor_value.sensor.id = 'Spalte 1')


Was soll denn tabelle_sensor_value.sensor.id sein?
Und warum der Wert Spalte 1?


----------



## gondor (8. Feb 2005)

so... wieder @home.

jetzt zu deinen fragen:

- Wofür brauchst du eine temp-Tabelle?

wie soll ich sonst das file gleich richtig in die tabelle_sensor_wert übernehmen? kann dieses nur (nach meinen wissensstand) komplett (alle spalten) in eine tabelle laden. das geht mit dem mysql-befehl:

'LOAD DATA INFILE...'

temp_tabelle (zeit, S01H011, S01H012, S02H021, S02H022, ...)

da die spaltennamen unterschiedlich sein müssen, aber ein sensor 2 einheiten aufnehmen kann, wird zu jedem sensor
entweder die 1 für °C oder die 2 für %rH angefügt. diese tabelle wird erzeugt und die daten aus der datei per mysql-befehl eingelesen...

oder geht das auch anders?

- Welche Datensätze willst du in die Tabelle sensor_wert_value einfügen?

in tabelle_sensor_value müssen alle sensorwerte mit deren zeitwert gefüllt werden. die struktur dieser tabelle ist folgende:

(id, sensor_id, protokoll_id, sensor_time, sensor_value)

sensor_id referenziert auf tabelle_sensor, wo die namen der sensoren festgelegt sind:

tabelle_sensor (id, name, einheit_id)

1, S01H01, 1
2, S01H01, 2
3, S02H01, 1
4, S02H01, 2

die einheit_id referenziert tabelle_einheit (id, name)

1, °C
2, %rH

also muss ich die erste spalte (zeit) und die zweite spalte (°C-sensor) aus tabelle_temp folgend in die andere tabelle füllen:

INSERT INTO tabelle_sensor_value VALUES (1, 1, 1, 2004-12-12-13:00:10, 2.000000)

sensor_id sagt, dass es sich hier um sensor 1 (°C) handelt...

danach die anderen werte. also wieder erste spalte (zeit) und dritte spalte (%rH-sensor) aus tabelle_temp folgend in tabelle_sensor_value füllen:

INSERT INTO tabelle_sensor_value VALUES (1, 2, 1, 2004-12-12-13:00:10, 2.000000)

sensor_id sagt, dass es sich hier um sensor 1 (%rH) handelt...

- Was soll denn tabelle_sensor_value.sensor.id sein?

wie schon oben geschrieben, die referenz zum sensornamen.

Und warum der Wert Spalte 1?

hm, das mit dem WHERE war falsch gedacht. war gestern schon zu spät...

---------

so, hoffentlich kannst du was damit anfangen. wäre natürlich klasse, wenn ich die sensor-werte so 'unkompliziert' wie möglich in meine tabelle bekomme. bei mir müsste ich für jede sensor-spalte eine iteration machen. das ist bei werten >300.000 pro sensor eine bestimmt lange berechnungszeit der cpu...

gondor(..)


----------



## foobar (8. Feb 2005)

> wie soll ich sonst das file gleich richtig in die tabelle_sensor_wert übernehmen? kann dieses nur (nach meinen wissensstand) komplett (alle spalten) in eine tabelle laden. das geht mit dem mysql-befehl:
> 
> 'LOAD DATA INFILE...'
> oder geht das auch anders?


Das würde ich so nicht machen. 

Ich habe mir das so gedacht: 
Du liest das File ein und erstellst aus dem Header Sensor-Objekte und aus den Daten entsprechende Data-Objekte. Da es sich anscheinend um eine große Datenmenge handelt, mußt du die Daten einfach zeilenweise einlesen und dann daraus Daten und Sensor-Objekte erzeugen. Diese Objekte übergibst du dann an eine Klasse die dann die Daten, mit ihren dazugehörigen Foreign-Keys in die DB schreibt.


Wie liest du die Daten denn jetzt ein? 
Poste doch mal etwas Code.


----------



## gondor (8. Feb 2005)

hm... würde das wirklich schneller gehen? laut mysql:

[..] Das LOAD DATA INFILE-Statement liest Zeilen aus einer Textdatei in eine Tabelle mit sehr hoher Geschwindigkeit [..]

wie ich die daten einlese?

naja, ganz einfach. über ein fileChooser lese ich die datei ein, bestimme die anzahl der sensoren und deren namen aus dem header, erzeuge mit create dann eine tabelle (aus den headerwerten) und importiere mit dem befehl LOAD DATA INFILE 'datei.txt' INTO TABLE tabelle_temp TERMINATED BY '\t' LINES TERMINATED BY '\n' IGNORE <Anzahl Headerzeilen> LINES] (zeit, S01H011, S01H012, S02H011, S02H012, ...)

soll ich jetzt immer noch code posten?

wegen den objekten. wie würde das denn dann ausehen? ist das wirklich ähnliches schnell?

gondor(..)


----------



## foobar (8. Feb 2005)

Vergiss das Load Data infile. 
Mach das besser zu Fuß, aber dafür ohne Systemcalls. Über Performance-Optimierungen kannst du dir später immer noch Gedanken machen, zuerst muß das Programm aber laufen.

Hier ist ein grober Entwurf wie der Parser aussehen könnte:


```
package sensorreader;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class HeaderReader
{
    private String fileName;
    private List sensors;
    public HeaderReader(String fileName)
    {
        this.fileName = fileName;
        this.sensors = new Vector();
        this.readFile();
    }
    
    private void readFile()
    {
        BufferedReader br = null;
        try
        {
            br = new BufferedReader(new FileReader(this.fileName));
            String buffer = null;
            while((buffer = br.readLine()) != null)
            {
                if (buffer.matches("Zeit \\[.*?"))
                {
                    this.sensors = this.parseHeader( buffer );
                    System.out.println("header parsed");
                }
                if ( ! sensors.isEmpty())
                {
                    this.parseData( buffer );
                }
            }
        }
        catch (FileNotFoundException e)
        {
            e.printStackTrace();
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
        
        
        
    }
    
    private void parseData(String input)
    {
        String[] tokens = input.split(" ");
        for (int i = 0; i < tokens.length; i++)
        {
            SensorHeader header =  ((SensorHeader)this.sensors.get( i ));
            System.out.println("Sensor name: " + header.getName() +  " type: "+  header.getType().getId() +" data " + tokens[i]);
        }
    }
    
    
    private List parseHeader(String input)
    {
        List header = new Vector();
        String[] lines = input.split(";");
        Pattern p      = Pattern.compile("(.*?)\\s*\\[(.*?)\\]");
        for(int i =0; i < lines.length; i++)
        {
            Matcher m = p.matcher(lines[i]);
            if(m.matches())
            { 
                SensorHeader s = null;
                //System.out.println("Header: " + m.group(1) + " Value: " + m.group(2));
                if ("°C".equals(m.group(2)))
                {
                    s = new SensorHeader(m.group(1), Type.DEGREE);
                }
                else
                {
                    s = new SensorHeader(m.group(1), Type.HUMIDITY);
                }
                header.add( s );
            }
        }
        return header;
    }
    
    
    public static void main(String[] args)
    {
        new HeaderReader("/home/steffen/sensor.dat");
    }
}
```



```
package sensorreader;

class SensorHeader
{
    private String name;
    private Type type;
    
    public SensorHeader(String name, Type type)
    {
        this.name = name;
        this.type = type;
    }
    
    public String getName()
    {
        return this.name;
    }
    
    public Type getType()
    {
        return this.type;
    }
}
```



```
package sensorreader;

class Type
{
    private int id;
    public static final Type DEGREE = new Type(1);
    public static final Type HUMIDITY = new Type(2);
    private Type(int id)
    {
        this.id = id;
    }
    
    public int getId()
    {
        return this.id;
    }
}
```


Alles was jetzt noch fehlt ist eine Klasse die den Datenbankzugriff regelt, aber das ist eine Kleinigkeit.


----------



## gondor (9. Feb 2005)

hallo foobar!

mal wieder ein großes dankeschön für deinen ehrgeiz. bist mir eine große hilfe... ehrlich!

ich habe deine klasse mal implmentiert. die ausgabe sieht folgend aus:


```
header parsed

Sensor name: Zeit type: 2 data Zeit

Sensor name: S1-H01 type: 1 data [s];S1-H01

Sensor name: S1-H01 type: 2 data [°C];S1-H01

Sensor name: S1-H02 type: 1 data [%rH];S1-H02

Sensor name: S1-H02 type: 2 data [°C];S1-H02

Sensor name: S1-H03 type: 1 data [%rH];S1-H03[°C];S1-H03[%rH];S1-H04[°C];S1-H04[%rH];

Sensor name: Zeit type: 2 data 2004-03-02

Sensor name: S1-H01 type: 1 data 00:00:01	1.000000	2.000000	3.000000	4.000000	5.000000	6.000000	7.000000	8.000000

Sensor name: Zeit type: 2 data 2004-03-02

Sensor name: S1-H01 type: 1 data 00:00:02	-20.000000	0.000000	-20.000000	0.000000	-20.000000	0.000000	-20.000000	1.000000

Sensor name: Zeit type: 2 data 2004-03-02

Sensor name: S1-H01 type: 1 data 00:00:03	-20.000000	0.000000	-20.000000	0.000000	-20.000000	0.000000	-20.000000	2.000000

Sensor name: Zeit type: 2 data 2004-03-02

Sensor name: S1-H01 type: 1 data 00:00:04	-20.000000	0.000000	-20.000000	0.000000	-20.000000	0.000000	-20.000000	3.000000

Sensor name: Zeit type: 2 data 2004-03-02

Sensor name: S1-H01 type: 1 data 00:00:05	-20.000000	0.000000	-20.000000	0.000000	-20.000000	0.000000
```

nun meine anmerkungen bzw. fragen:

müsste ich nicht folgende ausgabe bekommen?


```
ausgabe für sensor S1-H01 Type 1

Sensor name: Zeit type: 2 data 2004-03-02 00:00:01
Sensor name: S1-H01 type: 1 data 1.000000

Sensor name: Zeit type: 2 data 2004-03-02 00:00:02
Sensor name: S1-H01 type: 1 data -20.000000

Sensor name: Zeit type: 2 data 2004-03-02 00:00:03
Sensor name: S1-H01 type: 1 data -20.000000

...

ausgabe für sensor S1-H01 Type 2

Sensor name: Zeit type: 2 data 2004-03-02 00:00:01
Sensor name: S1-H01 type: 2 data 1.000000

Sensor name: Zeit type: 2 data 2004-03-02 00:00:02
Sensor name: S1-H01 type: 2 data -20.000000

Sensor name: Zeit type: 2 data 2004-03-02 00:00:03
Sensor name: S1-H01 type: 2 data -20.000000
```
zumindest nur 'einen' wert pro sensor... da dieser ja nur 'ein' ergebnis liefern kann und den zu einer bestimmten (mess)-zeit. evtl. ist beim parsen von dem header evtl. etwas schief gelaufen? zumindest werden für die weiteren sensoren keine ausgaben mehr erzeugt...

dieses file lese ich ein:

```
DASYLab - V 7.00.03                                                                                      
Schaldbldname : ArcticCell3.0                                                                            
Datum 2004-03-09
Zeit 14:29:41                                                                     
Blocklaenge : 1                                                                                          
Delta : 0.000816327 sec.                                                                                 
Kanalzahl 8                                                                                            
Zeit [s];S1-H01 [°C];S1-H01 [%rH];S1-H02 [°C];S1-H02 [%rH];S1-H03[°C];S1-H03[%rH];S1-H04[°C];S1-H04[%rH];
2004-03-02 00:00:01	1.000000	2.000000	3.000000	4.000000	5.000000	6.000000	7.000000	8.000000
2004-03-02 00:00:02	-20.000000	0.000000	-20.000000	0.000000	-20.000000	0.000000	-20.000000	1.000000
2004-03-02 00:00:03	-20.000000	0.000000	-20.000000	0.000000	-20.000000	0.000000	-20.000000	2.000000
2004-03-02 00:00:04	-20.000000	0.000000	-20.000000	0.000000	-20.000000	0.000000	-20.000000	3.000000
2004-03-02 00:00:05	-20.000000	0.000000	-20.000000	0.000000	-20.000000	0.000000	-20.000000	4.000000
2004-03-02 00:00:06	-20.000000	0.000000	-20.000000	0.000000	-20.000000	0.000000	-20.000000	5.000000
2004-03-02 00:00:07	-20.000000	0.000000	-20.000000	0.000000	-20.000000	0.000000	-20.000000	6.000000
2004-03-02 00:00:08	-20.000000	0.000000	-20.000000	0.000000	-20.000000	0.000000	-20.000000	7.000000
...
```

zu dem performanz-problem:

die frage ist, ob das einlesen nicht nur stark 'rechenintensiv' ist, sondern das spätere schreiben in die 
tabelle auch viel performanz kosten kann? immerhin können bis > 500.000 zeilen in dem file sein, wovon
ich bei 8 sensoren 40.000.000 werte in die db schreibe. bedeutet 40.000.000mal ein INSERT INTO ... 
puh... macht da die mySQL überhaupt mit?

tja, solche fragen machen nicht gerade laune. laune macht, dass du mir in meiner lagen helfen willst.

hoffe weiterhin mit dir zu rechnen und das du noch am 'ball' bleibst 

bis morgen(?)

gondor(..)


----------



## foobar (9. Feb 2005)

Da ist mir ein kleiner Fehler unterlaufen.

```
if (buffer.matches("Zeit \\[.*?"))
                {
                    this.sensors = this.parseHeader( buffer );
                    System.out.println("header parsed");
                }
              else if ( ! sensors.isEmpty())
                {
                    this.parseData( buffer );
                }
```
Du mußt das zweite else, durch ein else if ersetzen.



> die frage ist, ob das einlesen nicht nur stark 'rechenintensiv' ist, sondern das spätere schreiben in die
> tabelle auch viel performanz kosten kann? immerhin können bis > 500.000 zeilen in dem file sein, wovon
> ich bei 8 sensoren 40.000.000 werte in die db schreibe. bedeutet 40.000.000mal ein INSERT INTO ...
> puh... macht da die mySQL überhaupt mit?


Bei so großen Datenmengen würde ich auf Foreign-Key-Constraints, zumindest beim einlesen verzichten. Möglicherweise aber auch komplett, aber das muß man später sehen. 
Ausserdem würde ich mit einem PreparedStatement arbeiten um die Performance zu erhöhen, da diese in der DB gecached werden.

BTW soll das Programm nur einmal laufen, oder soll es ein Tool werden um regelmäßig Berechnungen durchzuführen?




> tja, solche fragen machen nicht gerade laune. laune macht, dass du mir in meiner lagen helfen willst.


Keine Angst, das wird schon ;-)


----------



## gondor (9. Feb 2005)

oh... meno...

ich glaube der parser macht es doch noch nicht so ganz richtig:

```
Sensor name: Zeit type: 2 data 2004-03-02

Sensor name: S1-H01 type: 1 data 00:00:01	1.000000	2.000000	3.000000	4.000000	5.000000	6.000000	7.000000	8.000000

Sensor name: Zeit type: 2 data 2004-03-02

Sensor name: S1-H01 type: 1 data 00:00:02	-20.000000	0.000000	-20.000000	0.000000	-20.000000	0.000000	-20.000000	1.000000

Sensor name: Zeit type: 2 data 2004-03-02

Sensor name: S1-H01 type: 1 data 00:00:03	-20.000000	0.000000	-20.000000	0.000000	-20.000000	0.000000	-20.000000	2.000000

Sensor name: Zeit type: 2 data 2004-03-02

Sensor name: S1-H01 type: 1 data 00:00:04	-20.000000	0.000000	-20.000000	0.000000	-20.000000	0.000000	-20.000000	3.000000

Sensor name: Zeit type: 2 data 2004-03-02

Sensor name: S1-H01 type: 1 data 00:00:05	-20.000000	0.000000	-20.000000	0.000000	-20.000000	0.000000	-20.000000	4.000000

Sensor name: Zeit type: 2 data 2004-03-02

Sensor name: S1-H01 type: 1 data 00:00:06	-20.000000	0.000000	-20.000000	0.000000	-20.000000	0.000000	-20.000000	5.000000

Sensor name: Zeit type: 2 data 2004-03-02

Sensor name: S1-H01 type: 1 data 00:00:07	-20.000000	0.000000	-20.000000	0.000000	-20.000000	0.000000	-20.000000	6.000000

...
```

der sensor S1-H01 type: 1 hat doch nur diese werte :

```
1.000000
-20.000000
-20.000000
-20.000000
-20.000000
-20.000000
...
```
der sensor S1-H01 type: 2 hat doch nur diese werte:

```
2.000000
0.000000
0.000000
0.000000
0.000000
0.000000
...
```
die zeit muss sollte dieses format haben:

```
2004-03-02 00:00:01
2004-03-02 00:00:02
2004-03-02 00:00:03
2004-03-02 00:00:04
2004-03-02 00:00:05
...
```

für die anderen sensoren (S1-H02 [°C];S1-H02 [%rH];S1-H03[°C];...) werden die werte nicht generiert...



> Bei so großen Datenmengen würde ich auf Foreign-Key-Constraints, zumindest beim einlesen verzichten. Möglicherweise aber auch komplett, aber das muß man später sehen.


hm... dann hätte ich ja stets eine riesen tabelle, oder? ob das im sinn eines db-designs steht? bei einlesen spielen die fkey´s ja keine wesentliche rolle, da nur in tabelle_sensor_value die  werte geschrieben werden müssen. da kommt es doch nur auf die 'richtigen' übergabeparameter an.



> Ausserdem würde ich mit einem PreparedStatement arbeiten um die Performance zu erhöhen, da diese in der DB gecached werden.


danke für den tipp. hatte mit dieser anweisung noch nicht gearbeitet. muss ich mich mal reinfuchsen ;-)



> BTW soll das Programm nur einmal laufen, oder soll es ein Tool werden um regelmäßig Berechnungen durchzuführen?


also, das programm soll eine art framework für die mess-db darstellen. ihre aufgabe bezieht sich auf das einlesen eines mess-files, die betrachtung dessen werte und ein exportieren in eine andere datei. bei der betrachtung werden die werte in einer jTable dargestellt. dabei kann bzw. soll der user aussuchen dürfen welche sensor-typen er sehen will (nur °C, nur %rH oder alle), wieviel sensorwerte in einem versuch beteiligt gewesen waren, die dauer einer messung, ...



> Keine Angst, das wird schon



habe ich mich eigentlich schon mal bedankt? 

hoffe du hast auch weiterhin interesse...

gondor(..)


----------



## foobar (9. Feb 2005)

Also meine Testdaten sehen so aus:

```
DASYLab - V 7.00.03
Schaldbldname : ArcticCell3.0
Datum : 2004-03-09
Zeit : 14:29:41
Kanalzahl : 8
Zeit [s];S1-H01 [°C];S1-H01 [%rH];S1-H02 [°C];S1-H02 [%rH];S1-H03[°C];S1-H03[%rH];S1-H04[°C];S1-H04[%rH];
2004-12-12-13:00:10 1.000000 2.000000 3.000000 4.000000 5.000000 6.000000 7.000000
2004-12-12-13:00:20 -20.000000 0.000000 -20.000000 0.000000 -20.000000 0.000000 -20.000000
2004-12-12-13:00:30 -20.000000 0.000000 -20.000000 0.000000 -20.000000 0.000000 -20.000000
```

und die daraus resultierende Ausgabe so:


```
header parsed
Sensor name: Zeit type: 2 data 2004-12-12-13:00:10
Sensor name: S1-H01 type: 1 data 1.000000
Sensor name: S1-H01 type: 2 data 2.000000
Sensor name: S1-H02 type: 1 data 3.000000
Sensor name: S1-H02 type: 2 data 4.000000
Sensor name: S1-H03 type: 1 data 5.000000
Sensor name: S1-H03 type: 2 data 6.000000
Sensor name: S1-H04 type: 1 data 7.000000
Sensor name: Zeit type: 2 data 2004-12-12-13:00:20
Sensor name: S1-H01 type: 1 data -20.000000
Sensor name: S1-H01 type: 2 data 0.000000
Sensor name: S1-H02 type: 1 data -20.000000
Sensor name: S1-H02 type: 2 data 0.000000
Sensor name: S1-H03 type: 1 data -20.000000
Sensor name: S1-H03 type: 2 data 0.000000
Sensor name: S1-H04 type: 1 data -20.000000
Sensor name: Zeit type: 2 data 2004-12-12-13:00:30
Sensor name: S1-H01 type: 1 data -20.000000
Sensor name: S1-H01 type: 2 data 0.000000
Sensor name: S1-H02 type: 1 data -20.000000
Sensor name: S1-H02 type: 2 data 0.000000
Sensor name: S1-H03 type: 1 data -20.000000
Sensor name: S1-H03 type: 2 data 0.000000
Sensor name: S1-H04 type: 1 data -20.000000
```

Ist doch alles in Ordnung. 
Der Sensor 1 C wird dem Wert 1.000000 zugeordnet und der Sensor 1 %rH dem Wert 2.000000 und so weiter ....



> habe ich mich eigentlich schon mal bedankt?


Kein Thema ;-)


----------



## gondor (9. Feb 2005)

ah, da ist mir wohl im laufe des 'postings' ein fehler unterlaufen:

der zeitwert war an manchen falsch angegeben:

das datum und die zeit war in einem 'token':

2004-03-02-00:00:01

doch liegen diese in dem file getrennt vor:

2004-03-02 00:00:01


```
DASYLab - V 7.00.03                                                                                      
Schaldbldname : ArcticCell3.0                                                                            
Datum 2004-03-09 
Zeit 14:29:41                                                                      
Blocklaenge : 1                                                                                          
Delta : 0.000816327 sec.                                                                                  
Kanalzahl 8                                                                                            
Zeit [s];S1-H01 [°C];S1-H01 [%rH];S1-H02 [°C];S1-H02 [%rH];S1-H03[°C];S1-H03[%rH];S1-H04[°C];S1-H04[%rH]; 
2004-03-02 00:00:01   1.000000   2.000000   3.000000   4.000000   5.000000   6.000000   7.000000   8.000000 
2004-03-02 00:00:02   -20.000000   0.000000   -20.000000   0.000000   -20.000000   0.000000   -20.000000   1.000000 
2004-03-02 00:00:03   -20.000000   0.000000   -20.000000   0.000000   -20.000000   0.000000   -20.000000   2.000000 
2004-03-02 00:00:04   -20.000000   0.000000   -20.000000   0.000000   -20.000000   0.000000   -20.000000   3.000000 
2004-03-02 00:00:05   -20.000000   0.000000   -20.000000   0.000000   -20.000000   0.000000   -20.000000   4.000000 
2004-03-02 00:00:06   -20.000000   0.000000   -20.000000   0.000000   -20.000000   0.000000   -20.000000   5.000000 
2004-03-02 00:00:07   -20.000000   0.000000   -20.000000   0.000000   -20.000000   0.000000   -20.000000   6.000000 
2004-03-02 00:00:08   -20.000000   0.000000   -20.000000   0.000000   -20.000000   0.000000   -20.000000   7.000000 
...
```

kann man das einfach beheben?

gondor(..)


----------



## foobar (10. Feb 2005)

> kann man das einfach beheben?


Klar, denk mal drüber nach ;-)


----------



## gondor (19. Feb 2005)

@foobar

leider habe ich keinen lösungsweg,... wie kann ich datum und zeit verwenden?

es existiert ja kein '-' zwischen datum- und zeitwert.


```
header parsed 
Sensor name: Zeit type: 2 data 2004-12-12 13:00:10 
Sensor name: S1-H01 type: 1 data 1.000000 
Sensor name: S1-H01 type: 2 data 2.000000 
Sensor name: S1-H02 type: 1 data 3.000000 
Sensor name: S1-H02 type: 2 data 4.000000 
Sensor name: S1-H03 type: 1 data 5.000000 
Sensor name: S1-H03 type: 2 data 6.000000 
Sensor name: S1-H04 type: 1 data 7.000000 
Sensor name: Zeit type: 2 data 2004-12-12 13:00:20 
Sensor name: S1-H01 type: 1 data -20.000000 
Sensor name: S1-H01 type: 2 data 0.000000 
Sensor name: S1-H02 type: 1 data -20.000000
...
```

kannst du noch einmal helfen?

was ist, wenn die werte 'tab-getrennt' sind? muss man dann bei split(" ") das angeben --> split("/t") ???

gondor(..)


----------



## foobar (19. Feb 2005)

> was ist, wenn die werte 'tab-getrennt' sind? muss man dann bei split(" ") das angeben --> split("/t") ???


Jepp

Probier es doch einfach aus, dann weißt du es.


----------



## foobar (19. Feb 2005)

> leider habe ich keinen lösungsweg,... wie kann ich datum und zeit verwenden?


Wie sollen denn die Felder jetzt zugeordnet werden?
Ergibt für mich keinen Sinn Datum und Zeit zu trennen, da im Header auch nur ein Zeitfeld auftaucht.


----------



## gondor (24. Feb 2005)

hi foobar!

so, die daten bekomme ich nun in die tabelle ;-) das problem mit dem datetime/ time ist gelöst. 
doch habe ich (wie schon geahnt) ein problem mit der performance. das einlesen von 70 zeilen 
á 8 sensoren dauert so ca. 30 sek. da ich aber >300.000 zeilen habe, ist das einlesen zeitlich 
sehr langwierig und während dieser ist die chance eines systemausfalls hoch. system-ausgaben 
mache ich während des einlesen nicht. 

mein system:

p4 2GHz, 512MB

hast du eine lösung, wie die daten 'schneller' in die db kommen können? mit dem mysql-befehl 
'import data infile...' gingen selbst >8MB-dateien in wenigen sekunden in eine tabelle. 

danke für hilfe ;-)


----------



## foobar (24. Feb 2005)

Warum befürchtest du das dein System abstürzt?



> hast du eine lösung, wie die daten 'schneller' in die db kommen können?


Wie sieht denn dein Code aus?
Verwendest du PreparedStatements?
Hast du den MySql-Server optimiert?


----------



## gondor (25. Feb 2005)

ah, du hast schon geantwortet...

1. Wie sieht denn dein Code aus?

hier lese ich ein:


```
private boolean parseData_DateTime(C_ImportFile import_file_, int recordID_) {

        System.out.println("C_Import --> parseData_DateTime");

        String datetime = "0000-00-00 00:00:00";

        /*Error-Flag*/
        boolean error_parse = true;

        int progress_counter = 0;

        /*Sensoren*/
        List sensors = null;

        /*Sensor-Zeile*/
        String buffer = null;

        /*File wird gepuffert eingelesen*/
        BufferedReader br = null;

        try {

            br = new BufferedReader(new FileReader(import_file_.getAbsolutePath()));

            /*Sensoren*/
            sensors = new Vector();

            while ((buffer = br.readLine()) != null && !this.interrupted) {

                this.setValue(progress_counter++);

                if (buffer.matches("Zeit \\[.*?")) {

                    /*Header mit Sensoren einlesen*/
                    sensors = this.parseHeader(buffer);

                } else if (!sensors.isEmpty()) {

                    String[] tokens = buffer.split(this.seperator_property);

                    for (int i = 0; i < tokens.length; i++) {

                        SensorHeader header = ((SensorHeader) sensors.get(i));

                        int sensorID = measurement_sensor.getSensorID(header.getName(), header.getType().getId());

                        if (header.getType().getId() == C_HeaderConstant.UNIT_TIME_ID) {
                            datetime = tokens[i];
                        } else {
                            query_sensor_value.addSensorValue(sensorID, recordID_, datetime, Double.parseDouble(tokens[i]));
                        }
                    }
                }
            }

        } catch (FileNotFoundException ex) {
        
            error_parse = false;

        } catch (IOException ex) {

            error_parse = false;

        } catch (Exception ex) {

            error_parse = false;
        }

        return error_parse;
    }
```

hier schreibe ich in die DB:


```
public boolean addSensorValue(int sensorID_, int recordID_, String measurementTime_, double sensorValue_) {

        //System.out.println("C_DBQuerySensorValue --> addSensorValue (SensorID : " + sensorID_ + ", RecordID : " + recordID_ + ", Time : " + measurementTime_ + ", Value : " + sensorValue_ + ")");

        /*Error-Flag*/
        boolean update_flag = false;
        
        this.openConnection();
        
        //String command = "INSERT INTO " + C_SensorValueTable.TableName + " (" + C_SensorValueTable.SensorValueSensorID + ", " + C_SensorValueTable.SensorValueRecordID + ", " + C_SensorValueTable.SensorValueMeasurementTime + ", " + C_SensorValueTable.SensorValue + ") VALUES (" + sensorID_ + ", " + recordID_ + ", '" + measurementTime_ + "', " + sensorValue_ + ");";

        String command = null;
        
        try {
            
            command = "INSERT INTO " + C_SensorValueTable.TableName + " ( " + C_SensorValueTable.SensorValueSensorID + ", " + C_SensorValueTable.SensorValueRecordID + ", " + C_SensorValueTable.SensorValueMeasurementTime + ", " + C_SensorValueTable.SensorValue + " ) VALUES (?, ?, ?, ?);";

            PreparedStatement pstmt = this.mySQL_connection.prepareStatement(command);

            pstmt.setInt(1, sensorID_);
            pstmt.setInt(2, recordID_);
            pstmt.setString(3, measurementTime_);
            pstmt.setDouble(4, sensorValue_);
            
            pstmt.execute();
            
            update_flag = true;
            
        } catch (SQLException ex) {

        }
        
        this.closeConnection();
                
        return update_flag;
    }
```

2. Verwendest du PreparedStatements?

jep, siehe oben... wäre ein batchUpdate evtl. besser bzw. schneller? 

3. Hast du den MySql-Server optimiert?

nein. was müsste man da machen? benutze innoDB als typ. zumindest sind
die tabellen mit OPTIMIZE behandelt....

4. Warum befürchtest du das dein System abstürzt?

weil der aufruft der methode 'parseData_DateTime' aus einem thread
heraus passiert. habe ich gemacht, um den import-algorithmus auch 
wieder abzubrechen, indem ich einen interrupt setze. könnte ja sein, 
dass dieser aus gründen nicht richtig funktioniert oder abgebrochen 
wird. desweiteren ist es merkwürdig, dass manchmal die schleife 
stecken bleibt...

hier eine fehlermeldung:


```
C_DBQuerySensorValue --> addSensorValue (SensorID : 26, RecordID : 13, Time : 2004-12-12 13:00:26, Value : 2.0)
C_DBQuerySensorValue --> addSensorValue (SensorID : 28, RecordID : 13, Time : 2004-12-12 13:00:26, Value : 3.0)
C_DBQuerySensorValue --> addSensorValue (SensorID : 29, RecordID : 13, Time : 2004-12-12 13:00:26, Value : 4.0)
Error: openConnection (Exception)

Exception: Communication link failure: java.net.SocketException, underlying cause: Socket closed

** BEGIN NESTED EXCEPTION ** 

java.net.SocketException
MESSAGE: Socket closed

STACKTRACE:

java.net.SocketException: Socket closed

	at java.net.SocketOutputStream.socketWrite0(Native Method)
	at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92)
	at java.net.SocketOutputStream.write(SocketOutputStream.java:136)
	at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:66)
	at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:124)
	at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:1758)
	at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:1721)
	at com.mysql.jdbc.MysqlIO.secureAuth411(MysqlIO.java:2467)
	at com.mysql.jdbc.MysqlIO.doHandshake(MysqlIO.java:813)
	at com.mysql.jdbc.Connection.createNewIO(Connection.java:1771)
	at com.mysql.jdbc.Connection.<init>(Connection.java:440)
	at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:400)
	at java.sql.DriverManager.getConnection(DriverManager.java:512)
	at java.sql.DriverManager.getConnection(DriverManager.java:171)
	at de.airbus.arctic.db.mysql.C_DBQuery.openConnection(C_DBQuery.java:160)
	at de.airbus.arctic.db.mysql.C_DBQuerySensorValue.addSensorValue(C_DBQuerySensorValue.java:62)
	at de.airbus.arctic.measurement.importDB.C_Import.parseData_DateTime(C_Import.java:603)
	at de.airbus.arctic.measurement.importDB.C_Import.run(C_Import.java:368)
	at de.airbus.arctic.gui.dialog.status.C_Dialog_Import.run(C_Dialog_Import.java:682)
	at java.lang.Thread.run(Thread.java:534)



** END NESTED EXCEPTION **

C_DBQuerySensorValue --> addSensorValue (SensorID : 31, RecordID : 13, Time : 2004-12-12 13:00:26, Value : 5.0)
C_DBQuerySensorValue --> addSensorValue (SensorID : 30, RecordID : 13, Time : 2004-12-12 13:00:26, Value : 6.0)
C_DBQuerySensorValue --> addSensorValue (SensorID : 32, RecordID : 13, Time : 2004-12-12 13:00:26, Value : 7.0)
```

mal funktioniert das 100%ig, und mal nicht... ganz komsich.

bis morgen 

gondor


----------

