Datei einlesen
-
Guten Tag,
ich bin seit mehreren Tagen an einer Aufgabe dran und komme einfach nicht auf die Lösung.
Ich muss eine txt-Datei einlesen. Diese sieht wie folgt aus:C2H5 12387C 2H 5 G 0300.00 5000.00 1000.00 1 7.19048023E+00 6.48407731E-03-6.42806469E-07-2.34787939E-10 3.88087728E-14 2 1.06745488E+04-1.47808924E+01 2.69070172E+00 8.71913321E-03 4.41983866E-06 3 9.33870314E-10-3.92777347E-12 1.28704043E+04 1.21381950E+01 4 C2H6 121686C 2H 6 G 0300.00 4000.00 1000.00 1 4.82593823E+00 1.38404286E-02-4.55725876E-06 6.72496725E-10-3.59816140E-14 2 -1.27177930E+04-5.23950672E+00 1.46253872E+00 1.54946670E-02 5.78050731E-06 3 -1.25783188E-08 4.58626713E-12-1.12391758E+04 1.44322949E+01Sie geht noch weiter, aber dadran ist meine Problem schon zu erkennen.
Ich darf außerdem die Datai nicht verändern.Ich hab es versucht mit:
std::string words; std::fstream file("test.txt"); while (file.good()) { file >> words; cout << words << endl; } file.close();oder auch mit:
while (getline(fin, line)) { cout << line << endl; istringstream tokenizer(line); string token; getline(tokenizer, token, ' '); istringstream float_iss(token); string f; float_iss >> f; cout << f << endl;Beides funktioniert nicht perfekt, da die Zwischenräume zwischen den Werten teilweise ein Minus aufweisen und daher das Programm die Werte nicht richtig einliest. Daher die Frage, wie ich es hinbekommen kann, dass es alle Werte einzeln einlesen kann. Kann mir dabei jemand helfen?
Vielen Dank
Streicher
-
Willst du die Datei als Text haben oder willst du mit den Werten auch rechnen? Denn du liest ja immer nur Text ein?
-
Ich muss damit später auch noch rechnen, aber dachte, dass ich sie zuerst als string einlese und später dann umforme. Aber wenn man das natürlich direkt am Anfang macht ist es praktischer.
-
Der std::istream operator >> ist für fast alles überladen, strings, double, float, int, ...
int main() { double d; std::cin >> d; }
-
Die Textdatei hat zeilenweise unterschiedliche Inhalte. Da muss man schon zunächst alles als unstrukturierten Text lesen und dann nach dem vorgefundenen Inhalt auswerten.
Vorschlag in C:
char zeile[96]; ifstream input; int size; size = sizeof(zeile); input.open("file.txt",ios::in); while(!input.eof()) { input.getline(zeile,size); // hier zeile zur Weiterverarbeitung auswerten } input.close();Die Überladungen von >> kann man erst einsetzen, wenn man weiss was in einer Zeile drinsteht!
edit: input.open(...) gehört da natürlich auch noch rein!
-
.good() ist schon angenehmer als .eof().
Und man weiß doch was in den Zeilen steht? string, string, string, unsigned, char, double, double, double, unsigned, [..], wieder von Vorne.
Zumindest der gezeigte Ausschnitt hat ein klares Schema.
-
cooky451 schrieb:
.good() ist schon angenehmer als .eof().
Es ist aber immer noch logisch falsch. Man weiß nicht, ob die Zeile die zur Weiterverarbeitung gegeben wird, überhaupt gültig war.
-
Was bedeutet C2H5 und die anderen Zeichen?
-
SeppJ schrieb:
cooky451 schrieb:
.good() ist schon angenehmer als .eof().
Es ist aber immer noch logisch falsch. Man weiß nicht, ob die Zeile die zur Weiterverarbeitung gegeben wird, überhaupt gültig war.
Jo, ich bin irgendwie von operator >> ausgegangen.
-
pyhax schrieb:
Was bedeutet C2H5 und die anderen Zeichen?
Spielt keine Rolle beim Lesen der Datei. Erst bei der Auswertung jeder eingelesenen Zeile in die Logik der Weiterverabeitung ist das von Interesse.
-
Kann es beim Lesen vorkommen, dass das EOF-Bit gesetzt ist, aber das Fail-Bit nicht?
-
pyhax schrieb:
Was bedeutet C2H5 und die anderen Zeichen?
C2H5 ist ein Ethylrest und C2H6 ist Ethan. Es handelt sich bei der Datei generell um viele chemische Elemente. Aber die spielen keine große Rolle.
Danke an berniebutt. Ich werde es mal versuchen und werde mich dann wieder melden.
-
#include <iostream> #include <conio.h> #include <fstream> int main() { std::ifstream lese_datei("datei.txt"); if(!lese_datei.is_open()) { std::cout << "Fehler, erkenne die Datei nicht!"; _getch(); exit(0); } char c; while(lese_datei.get(c)) { std::cout << c; } lese_datei.close(); _getch(); return 0; }Ist das die Lösung, die du suchst? Wenn du die einzelnen Wörter/Zahlen in einem String speichern willst, dann kannst du sie doch in der while-loop mit einer if-Anweisung lenken und einzelnd abfragen und speichern.
-
Gugelmoser schrieb:
Kann es beim Lesen vorkommen, dass das EOF-Bit gesetzt ist, aber das Fail-Bit nicht?
Für alle, die es interessiert: http://stdcxx.apache.org/doc/stdlibug/29-1.html
The flag eofbit is set when there is an attempt to read past the end of an input sequence. This occurs in the following two typical examples:
1. Assume the extraction happens character-wise. Once the last character is read, the stream is still in good state; eofbit is not yet set. Any subsequent extraction, however, is considered an attempt to read past the end of the input sequence. Thus, eofbit is set. (Later, we'll see that failbit is set as well.)
2. If you do not read character-wise, but extract an integer or a string, for example, you always read past the end of the input sequence. This is because the input operators read characters until they find a separator, or hit the end of the input sequence. Consequently, if the input contains the sequence ... 912749<eof> and an integer is extracted, the eofbit flag (but not failbit) is set.
Let's see whether failbit would be set in the previous examples:
1. After reading the last available character, the extraction not only reads past the end of the input sequence; it also fails to extract the requested character. Hence, failbit is set in addition to eofbit.
2. In this case, the result is different. Although the end of the input sequence is reached by extracting the integer, the input operation does not fail and the desired integer is indeed read. In this situation only the eofbit is set.
-
Streicher schrieb:
... dachte, dass ich sie zuerst als string einlese und später dann umforme.
das denken alle, die nicht wissen, wie Einlesen funktioniert. Das ist aber ein Holzweg.
Streicher schrieb:
.. da die Zwischenräume zwischen den Werten teilweise ein Minus aufweisen und daher das Programm die Werte nicht richtig einliest. Daher die Frage, wie ich es hinbekommen kann, dass es alle Werte einzeln einlesen kann.
Genau wie es cooky451 schon gesagt hat. Lese einfach die double-Werte aus der Datei. das '-'-Zeichen direkt hinter der Zahl stört da nicht, weil es eindeutig nicht mehr zur vorhergehenden Zahl gehört.
Streicher schrieb:
C2H5 12387C 2H 5 G 0300.00 5000.00 1000.00 1 7.19048023E+00 6.48407731E-03-6.42806469E-07-2.34787939E-10 3.88087728E-14 2 1.06745488E+04-1.47808924E+01 2.69070172E+00 8.71913321E-03 4.41983866E-06 3 9.33870314E-10-3.92777347E-12 1.28704043E+04 1.21381950E+01 4 C2H6 121686C 2H 6 G 0300.00 4000.00 1000.00 1 4.82593823E+00 1.38404286E-02-4.55725876E-06 6.72496725E-10-3.59816140E-14 2 -1.27177930E+04-5.23950672E+00 1.46253872E+00 1.54946670E-02 5.78050731E-06 3 -1.25783188E-08 4.58626713E-12-1.12391758E+04 1.44322949E+01Die Daten in der Datei wiederholen sich anscheinend alle 4 Zeilen. ich unterstelle mal, dass diese 4 Zeilen zu einem wie auch immer gearteten Eintrag zusammen gehören. Da ich nicht weiß, was das ist, nenne ich den mal 'Streicher'. Jetzt bleibt die Frage - was brauchst Du davon. Nur hast nur unscharf darauf geantwortet - ich unterstelle hier, dass Du die 14 Fließkommawerte benötigst, die in einem Eintrag stehen. Die Ziffer 1 bis 4, die am Zeilenende stehen, überlese ich mal und die Kopfzeile auch. Bleiben die 14 Werte - ohne sich auf die Anzahl festzulegen ..
#include <vector> struct Streicher { std::vector< double > m_data; };Damit man diese Struktur einlesen kann, füge ich einen Streaming-Operator hinzu:
#include <vector> struct Streicher { friend std::istream& operator>>( std::istream& in, Streicher& s ); std::vector< double > m_data; };Dieser Streaming-Operator befähigt einen, so einen Streicher-Eintrag direkt aus einer Datei zu lesen. Also in der Form:
Streicher s; ifstream file( "input.txt" ); file >> s; // Lese einen Streicher-Eintrag aus fileDen muss man jetzt natürlich implementieren:
std::istream& operator>>( std::istream& in, Streicher& s ) { s.m_data.clear(); // erst mal löschen, falls noch was drin stand in >> skipline; // Zeile 1 überlesen for( int zl=2; zl<=4; ++zl ) // Zeilen 2 bis 4 { double d; for( int i=0; i<(zl==4? 4: 5) && in >> d; ++i ) // in Zeile 2 und 3 fünf und in Zeile 4 drei Werte lesen s.m_data.push_back( d ); in >> skipline; // den Rest der Zeile überlesen (die Ziffern 2,3,4) } return in; }das 'skipline' gibt es so nicht in C++, so muss man das auch noch schreiben.
std::istream& skipline( std::istream& in ) { return in.ignore( std::numeric_limits< std::streamsize >::max(), '\n' ); // erfordert #include <limits> }Das war's eigentlig schon, In der Anwendung und alles zusammen sieht es dann so aus:
#include <vector> #include <limits> #include <fstream> #include <iostream> struct Streicher { friend std::istream& operator>>( std::istream& in, Streicher& s ); std::vector< double > m_data; }; std::istream& skipline( std::istream& in ) { return in.ignore( std::numeric_limits< std::streamsize >::max(), '\n' ); // erfordert #include <limits> } std::istream& operator>>( std::istream& in, Streicher& s ) { s.m_data.clear(); // erst mal löschen, falls noch was drin stand in >> skipline; // Zeile 1 überlesen for( int zl=2; zl<=4; ++zl ) // Zeilen 2 bis 4 { double d; for( int i=0; i<(zl==4? 4: 5) && in >> d; ++i ) // in Zeile 2 und 3 fünf und in Zeile 4 drei Werte lesen s.m_data.push_back( d ); in >> skipline; // den Rest der Zeile überlesen (Ziffern 2,3,4) } return in; } int main() { using namespace std; ifstream file("input.txt"); if( !file.is_open() ) { cerr << "Datei kann nicht geoeffnet werden" << endl; return -1; } for( Streicher s; file >> s; ) { // mache was mit 's' cout << s.m_data[0] << " ... " << s.m_data[13] << endl; } return 0; }Enthält die Datei 'input.txt' den oben beschriebenen Inhalt, so erhält man als Ausgabe:
7.19048 ... 12.1382 4.82594 ... 14.4323Falls Du aus der 1.Zeile des Eintrags noch weitere Werte benötigst, so melde Dich noch mal.
:xmas2: Werner
-
Also das Programm funktioniert soweit perfekt. Vielen Dank schon mal werner! Jetzt hab ich nur noch ein kleines Problem die Datei fängt nicht direkt mit der Liste an, sondern mit:
THERMO 300.000 1000.000 5000.000 AR 120186AR 1 G 0300.00 5000.00 1000.00 1 2.50000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 2 -7.45375000E+02 4.36600065E+00 2.50000000E+00 0.00000000E+00 0.00000000E+00 3 0.00000000E+00 0.00000000E+00-7.45375000E+02 4.36600065E+00 4Sprich die ersten beiden Zeilen sind noch zusätzlich vorhanden. Die Frage ist, ob man die 2 Zeilen auch einfach überspringen kann? Wenn ja wie genau?
Schon mal "Danke" im voraus. Auf jedenfall kann man jetzt weiterprogrammieren.
-
Streicher schrieb:
Die Frage ist, ob man die 2 Zeilen auch einfach überspringen kann? Wenn ja wie genau?
Da musst du doch nur um
in >> skipline; // Zeile 1 überleseneine for-Schleife machen.
-
Streicher schrieb:
Also das Programm funktioniert soweit perfekt. Vielen Dank schon mal werner! Jetzt hab ich nur noch ein kleines Problem die Datei fängt nicht direkt mit der Liste an, sondern mit:
THERMO 300.000 1000.000 5000.000 AR 120186AR 1 G 0300.00 5000.00 1000.00 1 2.50000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 0.00000000E+00 2 -7.45375000E+02 4.36600065E+00 2.50000000E+00 0.00000000E+00 0.00000000E+00 3 0.00000000E+00 0.00000000E+00-7.45375000E+02 4.36600065E+00 4Sprich die ersten beiden Zeilen sind noch zusätzlich vorhanden. Die Frage ist, ob man die 2 Zeilen auch einfach überspringen kann? Wenn ja wie genau?
Füge in meinem Code vor der Zeile 40 (also unmittelbar vor der for-Schleife) folgende Zeile ein:
file >> skipline >> skipline; // ersten 2 Zeilen überlesen:xmas2: Werner
-
Danke, hat geklappt. Damit wäre jetzt die Tabelle eingelesen.

Wenn ich noch Fragen habe melde ich mich, aber erstmal müsste es ausreichen.
-
Ich bin's nochmal:
Das Programm läuft soweit, aber ich kann damit noch nicht wirklich arbeiten. Denn ich bräuchte ein Feld welches alle eingelesenen Werte beinhaltet. Ich hab es mit mehreren Varianten von Feldern versucht, aber es klappt leider nie. Da es gleichzeitig mit den Feldern hochzählen muss, aber die vorhandene for-Schleife nach 14 Feldern wieder von vorne anfängt.Hat jemand dazu eine Idee wie man alle eingelesenen Werte abspeichern kann?