# csv-Datei ein und auslesen



## Stopthewar (11. Juni 2007)

Hi,

bin n neuling auf dem gebiet. Hab die Aufgabe bekommen mal in und aus na csv datei was zu lesen.

würde mich über eine kleine Einführung freuen.

Mfg

Stopthewar


----------



## con-f-use (11. Juni 2007)

Dateizugriffe über Streams


----------



## Stopthewar (11. Juni 2007)

con-f-use hat gesagt.:


> Dateizugriffe über Streams



danke erstmal für deine Antwort! Hab mir das ganze mal durchgelesen. Hab leider keine lösung für mein Problem gefunden.

csv:   test1;test2;test3;.......

so schaut die Datei aus. Muss jetzt im endefekt das rauslesen und in der Console als:

test1
test2
test3

ausgeben.

Bitte um Hilfe. Danke im vorraus.

Mfg

Stopthewar


----------



## con-f-use (11. Juni 2007)

Hab zwar keine Ahnung, was eine .csv-Datei ist, aber was du da willst könnte man z.B. so bewerkstelligen:
	
	
	



```
#include <fstream>
#include <iostream>
#include <string>

// Um Schreibarbeit zu sparen
    using namespace std;

/*****************************************************************************
 * Konsolenprogramm um eine Datei auszulesen und ihren Inhalt auszugeben.
 * Der Erste übergebene Parameter (argv[1])  enthält den Pfad zur Datei. Alle
 * weiteren Parameter werden ignoriert. Existiert die Datei nicht, wird eine 
 * Fehlermeldung ausgegeben.
 *
 * Achtung: Kommentare in der Datei werden wie gewöhnlicher Inhalt behandelt.
 *
 * Benutzung: 
 *    commando [pfad]
 * Eingabdatei:
 *   test1;test2;test3;
 * Ausgabe:
 *   test1
 *   test2
 *   test3 
 *****************************************************************************/

int main( const int argc, const char *argv[] ) {
    // Arguemt handling -> Fehler wenn keine Datei angegen wird
        if ( argc<2 ) {
                   cout << "Bitte Argument angeben!" << endl;
            exit(1);
        }
    
    // Streamvariable setzten und überprüfen, ob öffnen gelungen
    // (Fehlermeldung wenn nicht gelungen)
        ifstream inputFile( argv[1] );
        if( !inputFile ) {
            cout << argv[1] << " Konnte nicht geöffnet werden!" << endl;
            exit(1);
        }

    // Datei in einer Schleife buchstabenweise auslesen
        while( !inputFile.eof() ) {
            // Aktullen Buchstaben lesen
                char currentChar;
                inputFile >> currentChar;
            switch (currentChar) {
                // Wenn Buchstabe Strichpunkt, Leerzeile ausgeben
                case ';':
                    cout << endl;
                    break;
                // Leerzeilen ignorieren
                case '\n':
                    break;
                // Leerzeichen ignorieren
                case ' ':
                    break;
                // Alle anderen Buchstaben ausgeben
                default:
                    cout << currentChar;
                    break;
            }
        }
    
    // Schließende Leerzeile ausgeben und Programm ordnungsgemäß verlassen
        cout << endl;
        return 0;
}
```
 So sachen wie Kommentare ignoriet das Programm noch, soll ja auch nur die Herangehensweise zeigen. Ansonsten bin ich ziemlicher C++Anfänger und es geht sicher noch eleganter. Verstehe nicht, wo du Probleme hast. Eigentlich hätte dir der Link oben schon reichen müssen.


----------



## deepthroat (11. Juni 2007)

Hi.


con-f-use hat gesagt.:


> Hab zwar keine Ahnung, was eine .csv-Datei ist


CSV - Comma/Character Separated Value Datei (siehe z.B. Wikipedia).



con-f-use hat gesagt.:


> , aber was du da willst könnte man z.B. so bewerkstelligen:


Naja, ganz richtig ist das nicht. Erstmal braucht man in C++ so gut wie nie die eof() Methode (weil es meistens nämlich falsch ist, so wie bei dir). Dann prüfst du nicht ob überhaupt erfolgreich eingelesen wurde und du liest die Daten falsch ein, da du jegliche Leerzeichen überliest.

Zuerst sollte man die Datei zeilenweise einlesen, da auf jeder Zeile ein Record steht. Die Felder des Records sind durch ein einzelnes Zeichen (meist Komma oder Semikolon) getrennt.

```
string zeile;
ifstream datei("...");

if (datei.is_open()) {
  while (getline(datei, zeile)) {
    // .. Zeile verarbeiten
  }
} else { /* Fehler */ }
```
Gruß


----------



## con-f-use (11. Juni 2007)

Danke Meister, sage ja, dass ich nicht so der Crack bin aber:
Dass ich die Leerzeichen überlese war mir durchaus ohne deinen überaus hilfreichen Kommentar kar. Dachte das wäre erwünscht. Ich hab mich da an seinem Beispiel orientert. Will sagen, mein Programm passt auf das, was ich geschreiben habe.
Außerdem muss mann, wenn man getline verwendet wieder ne Menge mit stringstreams oder ähnlichem rummachen, was einfach nur umständlich ist.


----------



## deepthroat (11. Juni 2007)

con-f-use hat gesagt.:


> Danke Meister, sage ja, dass ich nicht so der Crack bin aber:
> Dass ich die Leerzeichen überlese war mir durchaus ohne deinen überaus hilfreichen Kommentar kar. Dachte das wäre erwünscht.


Das Problem ist, das du die Leerzeichen (Tab, Leerraum und Zeilenende) gar nicht einliest weil der >> Operator diese Zeichen überspringt. Das heißt, du kannst gar nicht sagen wann ein Record endet und ein neuer beginnt. Außerdem wenn zwischen den Trennzeichen Leerzeichen stehen, läßt du die auch einfach unter den Tisch fallen.

Gruß


----------



## con-f-use (11. Juni 2007)

Ja toll, aber ich bin wie gesagt davon ausgagen (da ich ja nicht wusste, wie eine csv-Datei aufgebaut ist was ich auch gesagt habe), dass die Einträge in der Datei wie in seinem Beispiel aufgebaut sind, sprich:
Eine alphanumerische Zeichenkette, in der keine Whitespaces vorkommen, gefolgt von beliebig vielen Whitespaces, gefolgt von einem Semikolon sowie wieder beliebig vielen Whitspaceses und das ganze beliebig oft - die Semicola sind die einzigen Trenner und die Whitespaces, egal wo, sind unnötig. Das war die Prämisse unter der ich das Script geschrieben habe.

Mein Script hat auf jeden Fall die richtige Richtung gezeigt. So könnte man jetzt zum Beispiel auf die Idee kommen und die über getline erhaltene Zeile (ein Array aus Chrars) Elementweise durchzugehen (wie in meiner while-Schleife) um dann das Zeuch auch mit whitespaces auszugeben.

Deinen Beitrag fand ich da einfach recht klugerisch und unkonstruktiv - besonders den Verweis auf Wikipedia. Außerdem half das nur ein winziges Stück weiter, denn "// .. Zeile verarbeiten" und "/*Fehler*/" dürften die Sachen sein, die ihm noch eher Probleme bereiten könnten als die Sache mit getline(), denn wenn er nicht selbst auf die getline-Sache kommt, weiß er auch nicht, wie er stringstreams oder ähnliches dazu einsetzt im seine Zeilen zu zerlegen.

Hoffe die Sache ist damit geklärt und wir können uns wieder dem eigentlichen Thema widmen: Hier noch der Link zu String-Streams


----------



## deepthroat (11. Juni 2007)

con-f-use hat gesagt.:


> Deinen Beitrag fand ich da einfach recht klugerisch und unkonstruktiv - besonders den Verweis auf Wikipedia.


Das wird wohl vor allem daran liegen, das du keine Ahnung hast - deswegen kommt es dir wohl so vor. Ich habe nur ungefähr zum 40-zigsten Mal in diesem Forum erklärt wie man mit den iostream umgehen sollte und das man eof() nicht verwendet.

Dein Beitrag war insofern sehr schlecht, weil ein Anfänger sich die falschen Ansätze aneignet und sich dann später irgendwann fragt warum das irgendwie nicht richtig funktioniert.



> Außerdem half das nur ein winziges Stück weiter, denn "// .. Zeile verarbeiten" und "/*Fehler*/" dürften die Sachen sein, die ihm noch eher Probleme bereiten könnten als die Sache mit getline(), denn wenn er nicht selbst auf die getline-Sache kommt, weiß er auch nicht, wie er stringstreams oder ähnliches dazu einsetzt im seine Zeilen zu zerlegen.


Es ging mir nicht um das getline. Ich habe nur erstmal die gröbsten Fehler berichtigt und eine andere (in meinen Augen) bessere Vorgehensweise vorgeschlagen, denn ich war etwas in Eile - Vorlesung fing in 5 min an.

Zur Vervollständigung:

```
#include <iostream>
#include <sstream>
#include <string>

using namespace std;

int main() 
{
  string line;

  while (getline(cin, line)) {
    istringstream record(line);
    string field;
    
    while (getline(record, field, ';')) {
      cout << field << endl;
    }
  }  
}
```
Gruß


			
				Dieter Nuhr hat gesagt.:
			
		

> Wenn man keine Ahnung hat - einfach mal Fresse halten.



PS: OK, man müßte jetzt statt cin natürlich einen ifstream benutzen.


----------



## con-f-use (11. Juni 2007)

Bin immernoch der Meinung, dass meine Lösung auf das Problem genau so gut ist wie deine. Ich darf dich noch auf einen Grundsatz der Programmierung hinweisen: There is more than one way to do it.
Man könnte z.B. auch sagen, dass es unübersichtlicher, schlechter Stil ist in einer Schleife ausdrücke wie dein getline zu packen. Das tu ich aber nicht, weil ich einsehe, das es hier eine sinnvolle und elegante verkürzung ist.

Und wenn du mal wieder wenig Zeit hast, weil du ja ein großer, toller Student bist, dann würde ich mir zwei Mal überlegen ob ich einen Flamewar starte oder überhaupt hier poste und ein unfertiges Script hinrotze.

Und jetzt enschuldige mich bitte, habe ja auch keine Zeit, muss ja noch Kontinuumsmechanik lernen.


----------



## deepthroat (12. Juni 2007)

con-f-use hat gesagt.:


> Bin immernoch der Meinung, dass meine Lösung auf das Problem genau so gut ist wie deine. Ich darf dich noch auf einen Grundsatz der Programmierung hinweisen: There is more than one way to do it.


Ich glaube du hast mich immer noch nicht so ganz verstanden. Es gibt sicherlich mehrere Wege etwas zu programmieren, aber dann sollten die Programme auch das gleiche Resultat bei gleicher Eingabe liefern. 

Das was du geschrieben hast, enthielt aber grundlegende Fehler. Und somit kommt mit Sicherheit nicht immer das gleiche Ergebnis heraus wie bei meinem Programm. Ob man nun zeilenweise oder zeichenweise einliest ist im Grunde egal - man muss es nur richtig tun. Wenn du jetzt die Fehler mit dem eof() berichtigst, die Überprüfung der Eingabe einbaust und evtl. noch den Stream noskipws übergibst, dann wäre es eine äquivalente Lösung.



con-f-use hat gesagt.:


> Man könnte z.B. auch sagen, dass es unübersichtlicher, schlechter Stil ist in einer Schleife ausdrücke wie dein getline zu packen. Das tu ich aber nicht, weil ich einsehe, das es hier eine sinnvolle und elegante verkürzung ist.


Das ist das Standard-Idiom welches man anwendet um zeilenweise einzulesen. Wenn man es unbedingt anders machen will, sollte man schon gute Gründe haben oder muß es sich zumindest gut überlegen damit es nicht falsch wird. Außerdem finde ich, das es sehr gut ausdrückt was gemeint ist: "solange eine Zeile von cin nach line gelesen werden kann...".



con-f-use hat gesagt.:


> Und wenn du mal wieder wenig Zeit hast, weil du ja ein großer, toller Student bist, dann würde ich mir zwei Mal überlegen ob ich einen Flamewar starte oder überhaupt hier poste und ein unfertiges Script hinrotze.


Also erstmal bin ich eher mittelgroß und so ein toller Student auch nicht. Außerdem war es nicht meine Absicht einen Flamewar zu starten. Und ich finde mein lückenbehafteter Quelltext war durchaus sinnvoll.


con-f-use hat gesagt.:


> Und jetzt enschuldige mich bitte, habe ja auch keine Zeit, muss ja noch Kontinuumsmechanik lernen.


Na dann, viel Erfolg.

Gruß


----------



## Stopthewar (12. Juni 2007)

Hi,

danke für eure postings aber das hat sich schon erledigt.

Mfg

Stopthewar


----------

