# Csv-Datei einlesen



## Lukas0521 (14. Jan 2019)

Hallo zusammen,

ich möchte eine Tabelle im Csv Format, die ursprünglich 3 spalten hatte einlesen. Dabei würde ich später gerne auf jede ursprüngliche Zelle zugreifen. Zur Information es handelt sich um Länder und Infos dazu, also Text. Im Anhang habe ich einen Versuch gestartet, an dem aber gemeckert wird. 

Vielen Dank!


----------



## Robat (14. Jan 2019)

Indizes von Arrays fangen bei 0 an und nicht bei 1


----------



## Lukas0521 (14. Jan 2019)

Robat hat gesagt.:


> Indizes von Arrays fangen bei 0 an und nicht bei 1



Wenn ich in die eckigen klammern 0 und 1 einsetze passt es auch nicht oder steh ich grad komplett aufm Schlauch... . In welchem Ausdruck müsste ich was ändern?


----------



## Robat (14. Jan 2019)

Dann steht in deinem Array nicht das drin, was du erwartest .. 
Wie sieht denn deine CSV-Datei aus. Als Separator hast du ein Semikolon .. als Kommentar steht aber "use comma as separator"


----------



## Lukas0521 (14. Jan 2019)

Hab's gefunden, es stand noch Tabelle 1 drüber, nur zeigt r mir jetzt aufgrund der while schleife ja jedes erste Land an und nicht ausschließlich das aus der 1. Zeile, wie bekomm ich das noch hin?

Csv Datei sieht folgendermaßen aus:

Land1;Stadt;Bevölkerung;;;;
Land2;Stadt;Bevölkerung;;;;
Land3;Stadt;Bevölkerung;;;;


----------



## Robat (14. Jan 2019)

Irgendwas muss wohl an deiner CSV-Datei falsch sein. Ich würde mir einfach mal den Array-Inhalt in der Schleife ausgeben lassen  über `Arrays.toString(..)`
Ansonsten hier noch mal ein Beispiel:

```
String data = "Land1;Hauptstadt;Einwohner;;;;\n" + "Land2;Hauptstadt;Einwohner;;;;\n" + "Land3;Hauptstadt;Einwohner;;;;";
try( BufferedReader reader = new BufferedReader(new StringReader(data))) {
    String line = "";
    while((line = reader.readLine()) != null) {
        String[] parts = line.split(";");
        System.out.println(parts[0] + " " + parts[1] + " " + parts[2]);
    }
} catch ( IOException e ) {
    e.printStackTrace();
}
```


----------



## Lukas0521 (14. Jan 2019)

```
[B]public[/B] [B]static[/B] [B]void[/B] main(String[] args) {
        String csvFile = "/Users/lukas/Desktop/laender.csv";
        String line = ";;;;";
        String cvsSplitBy = ";";
        [B]try[/B] (BufferedReader br = [B]new[/B] BufferedReader([B]new[/B] FileReader(csvFile))) {
            [B]while[/B] ((line = br.readLine()) != [B]null[/B]) {
                String[] country = line.split(cvsSplitBy);
                System.[B][I]out[/I][/B].println(country[0] + " " + country[1]);
            }
        } 
[B]       catch[/B] (IOException e) {
            e.printStackTrace();
        }

    }
```
Hier die Csv Datei, die ich leider nicht anhängen kann:

Land;Hauptstadt;Bevölkerung;;;;
Deutschland;Berlin;82.792.351;;;;
Italien;Rom;60483973;;;;
Österreich;Wien;8.822.267;;;;
Frankreich;Paris;66.991.000;;;;

Vielen Dank für deine Hilfe!

Als Rückgabe erhalte ich nun:
Land Hauptstadt
Deutschland Berlin
Italien Rom
Österreich Wien
Frankreich Paris

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0

Also soweit liest er alles korrekt ein, nur würde ich jetzt bestimmen, dass er mir nur die Österreicher auslesen soll,... also dass die Zeilen noch durchnummeriert wären. Ansonsten klappt ja jetzt schonmal was


----------



## Robat (14. Jan 2019)

Er liest noch nicht alles korrekt ein .. du bekommst ja eine ArrayIndexOutOfBoundsException.. kann es sein, dass du irgendwo in der CSV eine Leerzeile hast?


----------



## Lukas0521 (14. Jan 2019)

Gehe gerade alles durch aber um was es mir geht ist wie ich das ganze jetzt noch nach den zeilen trennen könnte und sagen kann dass ich eine bestimmt abfragen möchte. Die exception hat es mir davor nicht angezeigt also bin ich ggf. einfach auf ne leertaste gekommen.


----------



## Robat (14. Jan 2019)

Lukas0521 hat gesagt.:


> das ganze jetzt noch nach den zeilen trennen könnte


Machst du doch schon durch `(line = reader.readLine()` - dadurch erhälst du ja ein zeilenweises Einlesen


Lukas0521 hat gesagt.:


> dass er mir nur die Österreicher auslesen soll


Also darfst du nur die Datensätze ausgeben, wo `country[0].equals("Österreich")`


----------



## Lukas0521 (14. Jan 2019)

Robat hat gesagt.:


> Machst du doch schon durch `(line = reader.readLine()` - dadurch erhälst du ja ein zeilenweises Einlesen


Stimmt aber ich lese alles ein und ich würde gern sagen ich les nur die zweite Zeile ein... also sozusagen
`(line = reader.readLine(ZAHL(also 1,2,3,...)` aber ich kann da ja leider keine Zeile eintragen. Ich will also nur eine bestimmte Zeile einlesen. Sorry falls ich mich unklar ausgedrückt habe. Und ich will diese Zeile auslesen unabhängig ob da Österreich oder sonst was drin steht...


----------



## Robat (14. Jan 2019)

Du kannst nicht direkt auf eine Zeile einer Datei zugreifen. Wenn du Zeile x haben willst musst du vorher x-1 Zeilen einlesen. Aber du kannst ja mit einem Counter zählen, bei welcher Zeile du bist


----------



## Lukas0521 (14. Jan 2019)

Es handelt sich um ein Informatik Projekt, und ich würde diese Werte später in Google, in das Suchfeld einfügen und z.B. die Bevölkerungszahl immer wieder aktualisieren, und dazu müsste ich einfach z.B. ein beliebiges Land nehmen aus der ersten Spalte der Tabelle und dann die dazugehörigen Daten dazu auch haben. Könnt ich also mit der ersten Zeile beginnen, diese eingeben und dann weiter machen mit der nächsten, ohne dass er gleich mir alle auf einmal ausliest?


----------



## Robat (14. Jan 2019)

*Könntest* du machen, ja. Was sind denn die genauen Anforderungen an das Programm? 
Das Programm soll die CSV-Datei einlesen, für die Länder/Städte  die Bevölkerungszahlen aktualisieren und dann wieder in die CSV-Datei schreiben?


----------



## Lukas0521 (14. Jan 2019)

Korrekt. Müsste nur wissen, wie ich dabei eine Zeile nach der anderen einlese und nicht den ganzen Müll auf einmal ausgespuckt bekomme


----------



## Robat (14. Jan 2019)

Mir stellt sich da die Frage: Warum würdest du das wollen. Im Endeffekt musst du eh die Datei vorher komplett einlesen, bevor du die Daten aktualisieren kannst. Weil für das Schreiben gilt das gleiche wie für das Lesen - du kannst nicht einfach an Zeile x die Stelle y überschreiben.
Also lies die Daten doch einmal ein, pack sie in eine Klasse, aktualisiere die Daten, und schreib die aktualisierten Daten wieder in die Datei

```
class Entry {
   private String country;
   private String city;
   private long population;
   ....
}
```


```
List<Entry> entries = new ArrayList<>();
try(BufferedReader reader = new BufferedReader(...) {
   String line = "",
   while((line = reader.readLine()) != null) {
       Entry entry = parseEntry(line);
       entries.add(entry);
   }
} catch(IOException e) { .. }

// daten in entries überarbeiten
// daten neu in CSV Datei schreiben
```


----------



## Lukas0521 (14. Jan 2019)

Würde es nicht einfacher gehen einfach country[0] einfach einer variablen zuzuweisen? Problem ist halt dass Integer ein String nicht so leicht zuweisen lässt... Würde also int country=country[0]; oder int city=country[1]; immer neu definieren, wäre meiner Ansicht nach weniger aufwändig, würde dies gehen?


----------



## Robat (14. Jan 2019)

1. Sowohl `country[0]` als auch `country[1]` sind Strings (Land bzw Stadt) .. wie willst du diese in einer int Variable speichern?
2. Gehen tut vieles - mit einem Löffel bekomme ich den Nagel auch irgendwann in die Wand. Zumal ich das von oben nicht als aufwändig bezeichnen würde


----------



## Lukas0521 (14. Jan 2019)

Oke int ginge nicht, aber dass ich diese dann als Variablen speichere und so einfüge, würde dies nicht gehen, mit Listen müsst ich mich erst einlesen...;(. Weil wenn ich 
	
	
	
	





```
Country[0]
```
 eingebe kommt er nicht darauf klar, sondern führt es natürlich nicht aus...


----------



## Robat (14. Jan 2019)

Angenommen du würdest es so machen und `country[0]` in irgendeiner Variable speichern. Was hast du dann davon. Was würdest du dann damit machen wollen? Also wie würdest du dann weiter vorgehen wollen?


----------



## Lukas0521 (14. Jan 2019)

Ich würde sozusagen bevor ich diese in einer Liste speichere, würde ich einfach nachdem die erste Zeile ausgelesen wurde, diese in Google eingeben und vergleichen, und dann wird ja durch die while schleife die zweite Zeile ausgelesen und diese würd ich dann abgleichen, und immer so weiter...
Würde dies dann mit 
	
	
	
	





```
Desktop.[I]getDesktop[/I]().browse([B]new[/B] URI("www.google.de/#q="+Variable));
```
 suchen.
klappt leider nicht mit string, definiere ich aber mit integer eine zahl zuvor, wird diese in google gesucht


----------



## Robat (15. Jan 2019)

Lukas0521 hat gesagt.:


> Ich würde sozusagen bevor ich diese in einer Liste speichere, würde ich einfach nachdem die erste Zeile ausgelesen wurde, diese in Google eingeben und vergleichen,


Das kannst du ja theor. machen, also direkt den neuen/aktualisierten Wert abspeichern. Nur hättest du ja auch hier wieder eine Liste (wo du selber sagst, dass du dich erstmal einlesen musst)


----------



## Lukas0521 (15. Jan 2019)

Also komm ich um die Liste nicht drumrum oder? Welche Art muss ich dann nehmen, dass ich später die Vatiable mit dem Ländernamen der Liste zum Link oben hinzufügen kann


----------



## Robat (15. Jan 2019)

Lukas0521 hat gesagt.:


> Also komm ich um die Liste nicht drumrum oder


Du kannst auch Arrays nehmen. Bloß hast du dann das Problem, dass du nicht weißt wie viele Elemente du brauchst. Du müsstest das Array also nach jeder Iteration vergrößern. 


Lukas0521 hat gesagt.:


> Welche Art muss ich dann nehmen


ArrayList zB. Am sinnigsten wäre es, wie gesagt, eine eigene Klasse dafür zu erstellen, die Land, Stadt und Bevölkerung speichert. Du erstellst dann eine Liste, die Elemente von dieser Klasse beinhaltet.


----------



## Lukas0521 (15. Jan 2019)

```
ArrayList<String> arr = [B]new[/B] ArrayList<>();
                arr.add(country[0]);
                arr.add(country[1]);
                arr.add(country[2]);
```
Wie kann ich dann auch diese Liste zugreifen? Und Country[0] abfragen?


----------



## Robat (15. Jan 2019)

Über `arr.get(0)`, `arr.get(1)`, ... das wird dir aber in der Form wenig bringen. Wenn du es unbedingt ohne eigene Klasse machen willst, dann solltest du das komplette Array in der Liste abspeichern.

```
List<String[]> entries = new ArrayList<>();
try(BufferedReader reader = new BufferedReader(...) {
   String line = "",
   while((line = reader.readLine()) != null) {
       String[] entry = line.split(";");
       entries.add(entry);
   }
} catch(IOExceptione) { .. }

entries.get(0)[0] // -> Land des ersten Datensatzes
entries.get(1)[0] // -> Land des zweiten Datensatzes 
// ....
```


----------



## Lukas0521 (15. Jan 2019)

Bei mir passt da immer noch was nicht. Irgendwie kann ich entries noch nicht bekommen. Diese will ich dann hinter den Link setzen.


----------



## Lukas0521 (15. Jan 2019)

Hab geschafft was ich wollte, vielen vielen danke für deine Hilfe erstmal, hab jetzt nur noch das Problem, dass beim mir Leerzeichen ein Problem darstellen. Wie kann ich diese z.B. durch einen anderen Buchstaben ersetzen? Zur Not halt einfach ignorieren...


----------



## Lukas0521 (15. Jan 2019)

und wie kann ich nun noch ä ö ü darstellen, hab trotz dem Mac auf alles uff-8 umgestellt und trotzdem meckert er...


----------



## Robat (15. Jan 2019)

Was meinst du mit "er meckert"?


----------



## Lukas0521 (15. Jan 2019)

Mit System.outprint gibt er es mir richtig aus, nur öffnet er die website nicht, auch wenn in dieser ein ö stehen kann, hab ich schon ausprobiert. Ohne ö klappts... Und wie nehme ich dann automatisch den ersten Treffer?


----------



## mihe7 (15. Jan 2019)

Lukas0521 hat gesagt.:


> Mit System.outprint gibt er es mir richtig aus, nur öffnet er die website nicht, auch wenn in dieser ein ö stehen kann, hab ich schon ausprobiert


Du musst die Strings für die Verwendung in einer URL kodieren: https://docs.oracle.com/javase/8/docs/api/index.html?java/net/URLEncoder.html



Lukas0521 hat gesagt.:


> Ohne ö klappts... Und wie nehme ich dann automatisch den ersten Treffer?


Was hast Du vor?


----------



## Lukas0521 (15. Jan 2019)

mihe7 hat gesagt.:


> Du musst die Strings für die Verwendung in einer URL kodieren
> Was hast Du vor?


Vielen Dank! Ich schreib hinter Land A dann noch wikipedia und dann will ich, dass er automatisch die erste website öffnet(wikipedia) und dort in wikipedia vergleicht


----------



## Robat (15. Jan 2019)

Das was du, glaube ich zumindest, eher suchst, ist eine API, die dir für ein Land die aktuelle Bevölkerungszahl gibt.
Dazu kannst du bspw. http://api.population.io/ nehmen.
Wenn du einen GET Request an bspw http://api.population.io/1.0/population/Germany/today-and-tomorrow bekommst du eine Response mit folgenden Body

```
"total_population": [
       {
           "date": "2019-01-15",
           "population": 80513629
       },
       {
           "date": "2019-01-16",
           "population": 80513393
       }
   ]
```

Klar kannst du auch: Wikipedia-Artikel aufrufen -> Bevölkerungszahl parsen -> ... aber das ist wesentlich mehr Aufwand als ein einfacher HTTP-Request


----------



## Lukas0521 (17. Jan 2019)

Ich werde mal meine Variante versuchen, aber vielen Dank!


----------

