Daten auslesen aus einer Textdatei (.txt)

ZeroZ

Grünschnabel
Hallo Leute,

ich bin recht neu in C++ Programmierung. Hatte mal früher bisschen was gemacht und versuche gerade wieder rein zu kommen.

Meine Aufgabe besteht jetzt darin, aus einem Textdokument mit einer Menge (1000 Werte) an Zahlen auszulesen. Später muss ich diese verarbeiten z.B. alle 10 Werte mit den nächsten 10 vergleichen und das ganze mitteln damit man am Ende 10 Werte (von den ursprünglichen 1000) hat. Quasi über 10 Werte gemittelt.

Meine Hürde ist dabei eher das Korrekte auslesen der Textdatei.
Die folgendermaßen Formatiert ist:

1.321E-002 -1.123E-002 -1.543E-002

und das dann 1000 Zeilen mit unterschiedlichen Werten. Was konsistent bleibt sind die Anzahl der Zahlen Pro Wert und die Leerzeichenabstände.

Kann mir jemand vielleicht ein kleines Beispiel zum Auslesen zeigen? Ich habe schon einige Threads angeschaut, aber es war etwas schwer auf mein Beispiel zu interpretieren :/.

Liebe Grüße :)
 

cwriter

Erfahrenes Mitglied
C++:
#include <fstream>

//....

fstream f;
f.open("file.txt", std::fstream::out);
double v1, v2, v3;
f >> v1 >> v2 >> v3;

C:
FILE* f = fopen("file.txt", "r");
double v1, v2, v3;
fscanf(f, "%f %f %f", &v1, &v2, &v3);
fclose(f);

Die Loops rundherum (um >> und fscanf()) solltest du selbst hinkriegen. Du musst dann aus v1-3 auch noch Arrays machen.

Gruas
cwriter
 

ZeroZ

Grünschnabel
Also ich sehe die Hürden darin, dass die Daten immer erst ab der 15ten Zeile beginnen. Enden tun sie unterschiedlich. Weiterhin sind die Werte ja in einer Formatierung wie oben notiert (z.B. 1.321E-002). Kann das C++ korrekt interpretieren?

Es sind immer Drei Werte in einer Zeile mit gleichem Leerzeichen-Abstand. Das ist ja auch eine Hürde, wie man das definiert, damit das Programm überhaupt versteht, dass es drei Werte sind in einer Zeile?
 

cwriter

Erfahrenes Mitglied
Also ich sehe die Hürden darin, dass die Daten immer erst ab der 15ten Zeile beginnen.
Das stand so aber nicht im Ursprungspost.
(sollte auch nicht allzuviel ausmachen - probier's aus)

Weiterhin sind die Werte ja in einer Formatierung wie oben notiert (z.B. 1.321E-002). Kann das C++ korrekt interpretieren?
Das ist die "scientific notation" und ja, C++ kann das.

Es sind immer Drei Werte in einer Zeile mit gleichem Leerzeichen-Abstand. Das ist ja auch eine Hürde, wie man das definiert, damit das Programm überhaupt versteht, dass es drei Werte sind in einer Zeile?
Man liest einfach 3 Werte und nimmt dann an, dass man eine Zeile gelesen hat. Du kannst auch das Lesen nur einer einzigen Zeile erzwingen.

Gruss
cwriter
 

ZeroZ

Grünschnabel
Also ich muss 1000 bis 100.000 Zeilen einlesen. In jeder Zeile sind drei Werte mit gleich vielen Leerzeichen getrennt. Wichtig sind aber nur der erste und dritte Wert. Also wenn er eine Zeile einliest wird er feststellen, dass da drei Werte hintereinander stehen oder braucht man dafür eine Logik?
 

cwriter

Erfahrenes Mitglied
Also ich muss 1000 bis 100.000 Zeilen einlesen.
Du kannst auch 20 Gazillionen Zeilen einlesen, es ist egal (naja, irgendwann wird wohl der Speicher knapp, aber warum betonst du immer die Anzahl Zeilen?).

In jeder Zeile sind drei Werte mit gleich vielen Leerzeichen getrennt.
Die Anzahl Leerzeichen ist sogar egal. Es kann auch mal 100, mal 1000, mal 42, mal 1 Leerzeichen zwischen den Werten haben, scanf (bzw. istream::eek:perator>>(), was aber intern ziemlich ähnlich ist) ignoriert mehrere Leerzeichen einfach (bzw. liest es als /[\s]+/, falls du es auf RegEx ausdrücken willst).

Wichtig sind aber nur der erste und dritte Wert.
Schon wieder etwas neues? Ist aber Wurst, ob du dir den 2. Wert anschauen willst oder nicht - geparst werden muss er ohnehin. Du kannst beim fscanf folgendes tun:
C:
fscanf(f, "%f %*f %f", &v1, &v3);
wenn du den 2. Wert nicht haben willst, aber das ist eine vernachlässigbare Optimierung.

Also wenn er eine Zeile einliest wird er feststellen, dass da drei Werte hintereinander stehen oder braucht man dafür eine Logik?
Was willst du denn von mir hören? Der Code oben ist schon ziemlich minimal, viel einfacher wird es nicht. Warum willst du das wieder komplizierter machen?
Zeilen sind dem Programm (operator>> und scanf()) mehr oder weniger egal. Wenn du wirklich Zeilen unterscheiden willst, dann gibt es istream::getline() und fgets(), aber was hättest du davon?
C++:
char tmp[256];
f.getline(tmp, 256); //Liest eine Zeile, maximal aber 256 Bytes
sscanf(tmp, "%f %*f %f", &v1, &v3);

C:
char tmp[256];
fgets(tmp, 256, f); //Liest eine Zeile, maximal aber 256 Bytes
sscanf(tmp, "%f %*f %f", &v1, &v3);

Und dann loopen, beim fstream halt auf eof() prüfen, beim fgets() kannst du den Rückgabewert nehmen (while(fgets(...))).

Aber du fragst so viel... An sich ist Fragen ja immer gut, aber viele der Fragen liessen sich durch ein Laufenlassen des Programms auch direkt beantworten. Programmieren lernt man wie alles in erster Linie durchs Herumspielen damit, nicht durch andere, die darüber referieren.

Gruss
cwriter
 

ZeroZ

Grünschnabel
Danke cwriter. Ich frage, weil ich zu dem Zeitpunkt nicht die Möglichkeit hatte "herum zu spielen" wie du schon sagst. Und ich gebe dir da vollkommen recht. Ich werde morgen es mir vertieft ansehen und ausprobieren. Falls ich Fragen habe, würde ich meinen Code hier mal zeigen :)
 

ZeroZ

Grünschnabel
Also es funktioniert soweit, dass ich die Daten korrekt lese und ausgeben kann. Aber mit dem überspringen der ersten Zeilen war ich jetzt noch nicht erfolgreich. Ich habe da was probiert, aber es ändert nichts. Tipps?

Code:
123 213    1332 Hier steht ein Text.
321 123 1232 Hier ebenfalls.
123 234 2444 Noch mehr text mit Zahlen 456.525.
321 441 2414 Ende vom Text.

5.165655765E-004     -3.805380224E-003     -5.347641544E-002
1.453123879E-003     -2.422624042E-003     -6.035503311E-002

C++:
#include <fstream>
#include <iostream>
#include <string>
#include <sstream>
#include <limits>
#include <stdio.h>
using namespace st;
static const int start_line = 4;

int main()
{

    double v1, v2, v3;
  
    ifstream datei("... .txt");

    datei.ignore(start_line, '\n');
  
    datei >> v1 >> v2 >> v3;
  
  
    cout.precision(10);
    cout << v1 << endl;
    cout << v2 << endl;
    cout << v3 << endl;
  
    return 0;

  
}
 

cwriter

Erfahrenes Mitglied
Also es funktioniert soweit, dass ich die Daten korrekt lese und ausgeben kann.
Aber nicht mit dieser Eingabe. Es steht also noch Text am Beginn der Datei...


Aber mit dem überspringen der ersten Zeilen war ich jetzt noch nicht erfolgreich. Ich habe da was probiert, aber es ändert nichts


http://www.cplusplus.com/reference/istream/istream/ignore/ hat gesagt.:
Extracts characters from the input sequence and discards them, until either n characters have been extracted, or one compares equal to delim.

Du müsstest also ignore start_line mal ausführen, und mit der Maximalen Zeilenlänge als 1. Argument.
C++:
for(size_t i = 0; i < start_line; ++i) datei.ignore(256, '\n');

Und du willst wahrscheinlich kein static const int, sondern ein constexpr int verwenden.

Gruss
cwriter
 

ZeroZ

Grünschnabel
Ok alles klar, das mit den Zeilen überspringen funktioniert jetzt. Jetzt stehe ich aber vor der Hürde alle nötigen Zahlen in ein ausreichend großes double array zu speichern.

C++:
double v[4][2];

//Funktioniert
    datei    >> v[0][0] >> v[0][1] >> v[0][2] >> v[0][3];

//Funktioniert nicht
    datei     >> v[0][0];
    for (int j=0; j<3; j++)
        {
            v[0][j] >> v[0][j+1];
        }

Wäre gut wenn ich das in eine schleife einbauen könnte? Sonst müsste ich z.B. 400 double Werte von Hand eingeben wie oben ("Funktioniert").
 
Zuletzt bearbeitet: