# Maps auslesen



## SuperSheriff (4. Mai 2016)

Guten Tag zusammen,

wie der titel schon verrät geht es darum werte aus einer map auszulesen. Wir sollen title,author,album und duration aus einer map auslesen.

Hier noch die genaue Aufgabenstellung:

"Wie weiter oben bereits beschrieben, können einige Audio-Dateien (mp3, ogg) Meta-Daten (Tags) enthalten. Zur Bearbeitung dieser speziellen Art von Audio-Dateien haben wir die Klasse TaggedFile vorgesehen.  In diesen Tags können unter anderem Informationen zu Titel, Interpret und Album oder auch Informationen zu der Audio-Datei selbst enthalten sein.

Die statische Methode readTags() der Klasse studiplayer.basic.TagReader erlaubt es, die einzelnen Tags, also die einzelnen Werte der Meta-Daten, auszulesen.

Implementieren Sie in der Klasse TaggedFile die Methode public void readAndStoreTags(String pathname) Die Methode nutzt  studiplayer.basic.TagReader.readTags(), um die Tags “title“, “author“, “album“ und “duration“ aus derjenigen Datei auszulesen, deren Pfadname im Parameter pathname übergeben wird.

Falls die Tags belegt sind und sinnvolle Werte enthalten (also nicht null-Referenz oder leerer String oder Wert 0), sollen die ausgelesenen Werte in geeigneter Weise in Attributen der Klasse (oder in Attributen einer Basisklasse) gespeichert werden. Sofern nötig, ändern Sie hierzu die Sichtbarkeiten (private → protected) der Attribute in der Basisklasse.

Sollten einige Attribute bereits mit Werten belegt sein, hat der aus dem Tag gelesene Wert (falls sinnvoll) höhere Priorität und soll den alten Wert des Attributs überschreiben.
Beispiel: evtl. speichern sie bereits einen Titel oder Autor, weil die entsprechenden Attribute schon beim Aufruf von parseFilename() im Code der Basisklasse belegt wurden.

Erweitern Sie den Konstruktor der Klasse TaggedFile, der einen Pfadnamen als Argument erwartet, dahingehend, dass nach Aufruf des Konstruktors der Basisklasse ( super ) die Methode readAndStoreTags() mit einem geeigneten Argument aufgerufen wird.

Hinweis: Sie sollten ausnützen, das der Konstruktor der Basisklasse bereits eine Normalisierung und Überprüfung des Pfadnamens ausführt. Holen Sie sich dieses Ergebnis und nutzen Sie nicht den ungeprüften String"

Ehrlich gesagt weiß ich nicht genau wie man die map ausliest. Wenn ich es richtig verstanden hab hat jedes TaggedFileObjekt diese Tags welche mit readAndStoreTags() ausgelsen in einer Map gespeichert werden und dann ggf über die ursrprünglichen Attribute überschrieben.

Hier nun mein Code aber ich weiß ehrlich gesagt nicht wie ich das implementieren soll...


```
import java.util.Map;

import studiplayer.basic.BasicPlayer;
import studiplayer.basic.TagReader;

public class TaggedFile extends AudioFile {
 
    public TaggedFile(String pathname){
        super(pathname);
        readAndStoreTags(pathname);///
    }
 
    public TaggedFile(){
        super();
    }

    @Override
    public void play() {
        BasicPlayer.play(getPathname());
    }

    @Override
    public void togglePause() {
        BasicPlayer.togglePause();
     
    }

    @Override
    public void stop() {
        BasicPlayer.stop();
     
    }

    @Override
    public String getFormattedDuration() {
        return "";
    }

    @Override
    public String getFormattedPosition() {
        return "";
    }
 
    public static String timeFormatter(long  microtime){
     
        //Negative value of microtime
        if(microtime < 0){
            throw new RuntimeException("Negative Time value provided");
        }
     
        //Transformation from microseconds to seconds
        long timeInSeconds = microtime / 1000000;
     
        //Checking out of range 99:59 (mm:ss)
        if(timeInSeconds > 5999){
            throw new RuntimeException("Time value exceeds allowed format");
        }
     
        //Transformation in mm:ss
        long TimeInMinutes = timeInSeconds / 60;
        timeInSeconds = timeInSeconds  - (TimeInMinutes * 60);
        String parsedTime = "";
     
        if(TimeInMinutes < 10){
            parsedTime = "0" + TimeInMinutes;
        }else{
            parsedTime = "" + TimeInMinutes;
        }
        parsedTime = parsedTime + ":";
        if(timeInSeconds < 10){
            parsedTime = parsedTime + "0" + timeInSeconds;
        }else{
            parsedTime = parsedTime + "" + timeInSeconds;
        }
     
        return parsedTime;
    }
     
    public void readAndStoreTags(String pathname){
        Map <String,Object> tagMap = studiplayer.basic.TagReader.readTags(pathname);
     
        //http://www.java-tutorial.org/maps.html
        for( String key: tagMap.keySet()){
            if(tagMap.get(key) != null  && tagMap.get(key) != "")){
             
            }
        }
    } 
 
 

}
```

Vielen Dank im Voraus für eure Hilfe


----------



## kiwara (4. Mai 2016)

Eigentlich hast du mit der Schleife und der If-Abfrage schon die halbe Miete. In der Angabe steht, der Wert soll sinnvoll sein, was bedeutet du könntest noch auf leerString usw. überprüfen.
Das Problem dabei ist, dass ein Object gespeichert wird bzw. zurückgeliefert wird, aber aus der Angabe würde ich herauslesen dass das Object ein String ist(?).
Wenn das so ist, dann musst du einfach in der Schleife nur darauf achten, ob der Key, nun Autor, Titel, etc. ist und dann je danach den Wert speichern.


----------



## SuperSheriff (4. Mai 2016)

Mhm den leerString hab ich ja schon. Ich versteh das nicht so ganz. Mein Objekt Tagged file kann ja 4 tagged enthalten author,title,album und duration. Hat jedes dieser "Attribute" einen eigenen key? Und wie prüfe ich ob es diesen sinnvollen wert hat? Und muss ich die album und duration nicht noch als attribute für TaggedFile hinzufügen? weil bis jetzt hat ein TaggedObject ja nur einen pathname,filename,author und title.


----------



## kiwara (4. Mai 2016)

Ja. Mit dem Key "author" bekommst du den String des Autors, mit dem String "title", den Titel, aber mit dem String "duration" bekommst du den int(oder anderer Zahlenwert, vielleicht sogar String) länge.

Mit den Sinnvollen Wert, das stimmt das hast du schon mit ...get(key) != "". Problem ist halt, dass du ein Object zurück bekommst, was bedeutet du musst es vorher parsen, also in ein anderes Objekt, wie zum Beispiel String, wandeln. Weißt du welchen Datentyp die duration hat?


----------



## SuperSheriff (4. Mai 2016)

Also Duration müsste Mikrosekunden bzw long sein bzw wird in timeFormatte() zu mm:ss umgewandelt. Ehrlich gesagt weiß ich einfach nicht wie man das implementieren kann, kannst du mir mal ein beispiel mit author oder duration geben? und kann ich das leerstring problem mit isEmpty() lösen?

und title ist zum Beispiel mein schlüssel und was drin steht der Wert oder?

Und die reihenfolgen der taggs auhtor title album und duration weiß ich ja auch nicht, oder nach welchem muster wird die map befüllt sonst muss ich doch in jedme schleifenschritt tagMap.contains() machen mit jedem Tagg

Die schleife geht ja meine keys durch und wie bekomm ich nun raus ob da jzt der title oder author oder was auch immer drinsteht?


----------



## kiwara (4. Mai 2016)

```
for(String key : tagMap.keySet()){
    switch(key){
    case "author":   String author = (String) tagMap.get(key);
                           irgendeineSaveMethode(author);
                            break;
    case "title": String title = (String) tagMap.get(key);
                      irgendeineSaveMethode(title);
                      break;
    }
}
```
Natürlich kann man den Code leserfreundlicher gestalten, aber Refactoring kommt erst später. Als Beispiel genügt dies hoffentlich.


----------



## SuperSheriff (4. Mai 2016)

Danke. Wie bekomm ich das überschreiben hin? könnte ich es nicht mit einem setter machen?


----------



## kiwara (4. Mai 2016)

Ja das ist eine gute Idee


----------



## SuperSheriff (4. Mai 2016)

Okay allerdings ist das mit setter nicht so vorgesehen auf unseren übungsblatt und kann auch gut sein dass es dann später bei den Junittests nicht funktioniert. Fällt dir vlt noch eine alternativlösung ein, weil ich komme eigentlich nur auf die idee mit den settern

und warum funktioniert tagMap.get(key) nicht um einen setter aufzurufen? Müsste doch gehen oder?


----------



## kiwara (4. Mai 2016)

Irgendwie verstehe ich die Frage bzw. den Zusammenhang zwischen .get(key) und dem setter nicht.
In der Schleife, im Switch, kannst du dann einfach den Autor und Titel setzen. Entweder eben in einer anderen Klasse und in der anderen Klasse dann:


```
klasse.setAutor((String)tagMap.get(key); //so

//oder so
String author = (String) tagMap.get(key);
klasse.setAutor(author);
```


----------



## SuperSheriff (4. Mai 2016)

hab das nu so gemacht 

```
case "author": String newAuthor = (String) tagMap.get(key);
                                setAuthor(newAuthor);
                                break;
```

wie bekomme ich das noch mit duration hin, also zu schauen ob der wert != 0 ist


----------



## SuperSheriff (4. Mai 2016)

Habsj jetzt mal ausprogrammiert. Die duration ist glaub ich auch ein String


```
import java.util.Map;

import studiplayer.basic.BasicPlayer;
import studiplayer.basic.TagReader;

public class TaggedFile extends AudioFile {
  
    private String album;
    private String duration;
  
  
    public TaggedFile(String pathname){
        super(pathname);
        readAndStoreTags(pathname);///
    }
  
    public TaggedFile(){
        super();
    }

    @Override
    public void play() {
        BasicPlayer.play(getPathname());
    }

    @Override
    public void togglePause() {
        BasicPlayer.togglePause();
      
    }

    @Override
    public void stop() {
        BasicPlayer.stop();
      
    }

    @Override
    public String getFormattedDuration() {
        return "";
    }

    @Override
    public String getFormattedPosition() {
        return "";
    }
  
    public static String timeFormatter(long  microtime){
      
        //Negative value of microtime
        if(microtime < 0){
            throw new RuntimeException("Negative Time value provided");
        }
      
        //Transformation from microseconds to seconds
        long timeInSeconds = microtime / 1000000;
      
        //Checking out of range 99:59 (mm:ss)
        if(timeInSeconds > 5999){
            throw new RuntimeException("Time value exceeds allowed format");
        }
      
        //Transformation in mm:ss
        long TimeInMinutes = timeInSeconds / 60;
        timeInSeconds = timeInSeconds  - (TimeInMinutes * 60);
        String parsedTime = "";
      
        if(TimeInMinutes < 10){
            parsedTime = "0" + TimeInMinutes;
        }else{
            parsedTime = "" + TimeInMinutes;
        }
        parsedTime = parsedTime + ":";
        if(timeInSeconds < 10){
            parsedTime = parsedTime + "0" + timeInSeconds;
        }else{
            parsedTime = parsedTime + "" + timeInSeconds;
        }
      
        return parsedTime;
    }
      
    public void readAndStoreTags(String pathname){
        Map <String,Object> tagMap = studiplayer.basic.TagReader.readTags(pathname);
      
        //http://www.java-tutorial.org/maps.html
        for( String key: tagMap.keySet()){
            if(tagMap.get(key) != null &&tagMap.get(key) != "" && tagMap.get(key) != "duration"){
                switch(key){
                case "author": String newAuthor = (String) tagMap.get(key);
                                setAuthor(newAuthor);
                                break;
                case "title": String newTitle = (String) tagMap.get(key);
                                setTitle(newTitle);
                                break;
                case "album": album = (String) tagMap.get(key);
                                break;
                }
                  
                }else if(tagMap.get(key) == "duration" && tagMap.get(key) !=  "0"){
                    duration = (String) tagMap.get(key);
              
            }
        }
    }  
  
  

}
```

passt das so?


----------



## kiwara (4. Mai 2016)

du kannst in das switch auch das hinzufügen:

```
case "duration": String duration = timeFormatter((Long) tagMap.get(key));
                     setDuration(duration);
```


----------



## mrBrown (4. Mai 2016)

Es wäre zuerst mal Sinnvoll, rauszufinden, was in der Map steckt, anstatt einfach zu Casten, sonst gibts im schlechtesten Fall eine Exception.

Stringvergleiche auch nicht mit !=/==, sondern mit equals, du willst auf Inhaltsgleichheit prüfen, nicht auf Referenzgleichheit. In fast allen Fällen wird string1 immer != string2 sein, weil es zwei unterschiedliche Objekte sind, auch wenn sie den gleichen Inhalt haben.


----------



## kiwara (4. Mai 2016)

Es wäre mal sinnvoll es auszuführen und zu schauen was dabei rauskommt.


----------

