Anzahl der Zeichen in einer Textdatei auslesen?



  • Du kannst die Datei natuerlich auch gleich von hinten oeffnen.

    ifstream input;
    input.open("Example.txt", ios::ate);
    unsigned int ctr = input.tellg();
    input.close();
    

    Ansonsten fuer Windows kriegst du hier die Filesize raus.
    http://msdn.microsoft.com/en-us/library/windows/desktop/aa365739(v=vs.85).aspx



  • Arcoth schrieb:

    Und wo ist der nächste Link?

    Mhm, vielleicht hab ich Dich doch überschätzt?
    Aber einmal helfe ich Dir noch:
    Ohne das jetzt selbst überprüft zu haben, behaupte ich mal, er ist direkt unter dem ersten.


  • Mod

    Das reicht jetzt. Ich werde hier nicht meine Zeit damit verschwenden, dir irgendwas zu beweisen.

    ifstream input;
    input.open("Example.txt", ios::ate);
    

    Den Konstruktor von ifstream nicht ignorieren.

    ifstream input("Example.txt", ios::ate);
    

    Schließen muss man die Datei auch nicht, das macht der Destruktor. Und statt unsigned int den richtigen Typ nehmen.



  • Arcoth schrieb:

    Das reicht jetzt. Ich werde hier nicht meine Zeit damit verschwenden, dir irgendwas zu beweisen.

    ifstream input;
    input.open("Example.txt", ios::ate);
    

    Den Konstruktor von ifstream nicht ignorieren.

    ifstream input("Example.txt", ios::ate);
    

    Schließen muss man die Datei auch nicht, das macht der Destruktor. Und statt unsigned int den richtigen Typ nehmen.

    Hi,
    was ist denn der richtige Datentyp fuer tellg?

    Ouf overflow habe ich das dazu gefunden: http://stackoverflow.com/questions/10065323/how-to-collect-and-store-tellp-tellg-return-types

    Was den Konstruktor angeht ist doch der einzige Unterschied zwischen deinem Objekt zu meinem, dass ich das ifstream-Objekt nicht gleich mit einer Datei assoziiere, oder?

    Ich habe irgendwo gelesen, dass man sobald man mit einer Datei fertig ist sie so schnell wie moeglich wieder schliessen soll. Der Destruktor des ifstream Objektes wird ja erst aufgerufen, wenn das Objekt "out of scope" gegangen ist.

    Oder brauch ich mir die Muehe nicht machen?



  • Vielen Dank für die vielen Antworten.

    Ich habe jetzt

    ifstream file( "example.txt", ios::binary | ios::ate);
    return file.tellg();
    

    übernommen.

    Wie kann ich denn nun aber diesen Wert einer Variablen zuweisen?



  • Ich muss mich korrigieren. Diese Lösung scheint nicht zu funktionieren.

    Sobald ich

    ifstream file( source_file );
    

    durch

    ifstream file( source_file, ios::binary | ios::ate );
    	return file.tellg();
    

    ersetze, stürzt das Programm an der Stelle ab.


  • Mod

    djnforce schrieb:

    ersetze, stürzt das Programm an der Stelle ab.

    Das kann hunderte Ursachen haben. Siehe:
    http://www.c-plusplus.net/forum/304133

    Wie kann ich denn nun aber diesen Wert einer Variablen zuweisen?

    😕 Was hast du vor? Kannst du überhaupt C++?



  • Ich bin C++ Anfänger.

    Ich habe eine Textdatei mit über 10 000 Zeilen, aus der ich nur bestimmte Zahlen benötige.
    Diese werden untereinander in einer anderen Textdatei gespeichert. Das funktioniert super.

    Das ganze dauert aber ca. 1-2 Minuten und ich möchte den Nutzer nicht im ungewissen über den Fortschritt lassen.

    Deshalb möchte ich zu Anfang gerne wissen, wie viele Character die Ausgangsdatei hat um diese Zahl mit der zur Zeit durchsuchten Anzahl an Character zu vergleichen.

    So kann ich dann immer ausgeben lassen:
    10% 20% usw.

    Der gesamte Code:

    // This program will find specific information in the huge tripfile.
    // If you have some questions please feel free to ask ...
    // build: 13.11.2013
    
    #include <fstream>
    #include <string>
    #include <iostream>
    #include <iterator>
    #include <sstream>
    #include <math.h>
    #include <stdio.h>
    
    using namespace std;
    
    // "ignore_until" forces to ignore all words until a specific word is found
    
    void ignore_until(istream& is, const string& delim)
    {
    	string data;
    
    	while (is.good())
    	{
    		data.push_back((char) is.get());
    
    			if (data.find(delim) != string::npos) return;
    	}
    }
    
    int main()
    {
    	string source_file;
    	string target_file;
    	int opt;
    	float size;
    
    	cout << "Please choose one option:\n\n1- GPS coordinates \n2- GPS coordinates & fieldstrengths \n3- GPS coordinates & fieldstrengths & frequencies \n4- GPS coordinates & fieldstrengths & frequencies & Programm Identification\n";
    	cin >> opt;
    
    	cout << "\n\nsource file (example.txt):" << endl;
    	cin >> source_file; // type name of source file
    
    	cout << "\ntarget file (further_example.txt):" << endl;
    	cin >> target_file; // type name of target file
    
    	cout << "\nmerging still in progress (it may take a few minutes), please wait..." << endl;
    
    	ifstream file( source_file );
    	//size = file.tellg();
    
        if( !file.is_open() ) // could the file be opened?
            return -1;
    
        ofstream new_file( target_file ); // In this file we would like to save our data
        new_file.setf(ios::fixed); // no scientific output
    
    	// what we searching for:
    
    	const string what_reference = "<proxyf"; // Our search will start at the head of our source file
        const string what_coord = "Coord:(";					// we are looking for GPS coordinates
    	const string what_field = "Fieldstrength         : "; // we are looking for FM Fieldstrength
    	const string what_freq = "Frequency             : "; // we are looking for related frequency
    	const string what_pi = "PI                    : "; // PI --> Program Identification. Is a unique number for each radio station. You can check which station name is behind the number under http://www.fmlist.org (click on "continue as guest")
    
        string str; // do we need to check if we are starting in the head of the file
    
        for(char c; file.get(c);) // each time the loop pass we read one character
        {
            str += c; // This character we attach to the string 
    
    		if( str == what_reference ) // if this string matches the variable "what_reference" we know that we are in the file header and can start to read
            {
    			//#### read coordinates
    
    			ignore_until(file, what_coord); // ignore everything until "what_coord" appears
    
                double x;
                file >> x; // read first coordinate
    
                file.ignore( 1 ); // Ignore the comma
    
    			double y;
                file >> y; // read second coordninate
    
    			//#### read frequency
    
    			ignore_until(file, what_freq); // ignore everything until "what_freq" appears
    
    			double freq; 
    			file >> freq; // read frequency
    
    			//#### read PI --> Program Identification. Is a unique number for each radio station. You can check which station name is behind the number under http://www.fmlist.org (click on "continue as guest")
    
    			ignore_until(file, what_pi); // ignore everything until "what_pi" appears
    
    			string pi;
    			file >> pi; // read PI
    
    			//#### read fieldstrenth
    
    			ignore_until(file, what_field);// ignore everything until "what_field" appears
    
    			string value;
    			file >> value; // read fieldstrength
    
    			// write data to file
    
                if( file ) // was reading successful ?
    
                {	// reading was successful --> write data to file while recalculating coordinates (coordinate transformation)
    				if ( opt == 4 )
    					new_file << y * (360 / pow(2,32)) << ',' << x * (360 / pow(2,32)) << ',' << value << ',' << freq*0.001 << ',' << pi << '\n'; 
    				else
    				if ( opt == 3 )
    					new_file << y * (360 / pow(2,32)) << ',' << x * (360 / pow(2,32)) << ',' << value << ',' << freq*0.001 << '\n'; 
    				else
    				if ( opt == 2 )
    					new_file << y * (360 / pow(2,32)) << ',' << x * (360 / pow(2,32)) << ',' << value << '\n'; 
    				else
    				if ( opt == 1 )
    					new_file << y * (360 / pow(2,32)) << ',' << x * (360 / pow(2,32)) << '\n'; 
                }
    
                str.clear(); // we clear str and start again
            }
    
            else if( str.length() == what_coord.length())
            {
                // its necessary, don't ask why :-)
                str.erase( 0, 1 );
            }
    
    	}
    
    }
    

  • Mod

    djnforce schrieb:

    Das ganze dauert aber ca. 1-2 Minuten und ich möchte den Nutzer nicht im ungewissen über den Fortschritt lassen.

    😮 Das sollte eine Sache von Sekundenbruchteilen sein. Unwahrnehmbar schnell. Tausende Zeilen, selbst wenn die Zeilen tausende Zeichen lang sind, sind absolut gar nichts für einen Computer. Du machst sicherlich etwas furchtbar falsch. Hier sollte der Ansatz zur Verbesserung liegen.

    Ich habe eine Textdatei mit über 10 000 Zeilen, aus der ich nur bestimmte Zahlen benötige.

    Sicher, dass C++ hier das richtige Mittel ist? Das klingt nach einem Einzeiler für Konsolentools wie grep.

    Irgendwie kommt es mir so vor, als hätte ich das schon einmal geschrieben. *such* Hier:
    http://www.c-plusplus.net/forum/p2362383#2362383

    Zu deinem Code: Das sieht ungeheuer umständlich aus. Man liest nicht einzelne Zeichen, wenn man nicht muss. Man vergleicht nicht nach jedem Zeichen, wenn man nicht muss. Außerdem passt der Kontrollfluss deines Programms nicht zu dem, was du im anderen Thread als Aufgabe beschrieben hast, das Programm sollte nicht korrekt funktionieren. Du hast den Code abgeschrieben und verändert, ohne ihn zu verstehen, oder?

    Wenn es schon C++ für diese Aufgabe sein soll, dann lies doch einfach alles in einem Rutsch ein (oder in großen Blöcken) und durchsuch die Blöcke nach den Schlüsselwörtern. Etwas anderes macht grep übrigens auch nicht, weshalb das am Ende gleich schnell sein sollte (und im Zweifelsfall ist dein Programm langsamer, da grep ziemlich flott ist und du wahrscheinlich irgendwelche Fehler machst).



  • Ja das ist richtig. Ihr habt mir hier schonmal sehr geholfen.

    Ich habe jetzt aber eine Lösung für mein Problem:

    // data size
    	ifstream file1( source_file, ifstream::in | ifstream::binary );
    	file1.seekg(0, ios::end);
    	int fileSize = file1.tellg();
    	file1.close();
    
    	cout << fileSize << endl;
    

    Damit kann ich arbeiten 🙂

    Das Programm soll nicht perfekt sein. Es muss nur funktionieren...


  • Mod

    djnforce schrieb:

    Das Programm soll nicht perfekt sein. Es muss nur funktionieren...

    Es gibt einen Unterschied zwischen nicht-perfekt und schlecht. Du könntest mit einfacheren Mitteln in viel kürzerer Zeit ein viel besseres Ergebnis erreichen, wenn du dich nicht so verbissen an deine (abgeschriebene) Lösung klammern würdest. Ich habe irgendwie den Eindruck, dass outs Lösung aus dem anderen Thread nicht so ganz ernst gemeint war...


  • Mod

    Spaßeshalber vergleich doch mal die Geschwindigkeit (Compileroptimierungen nicht vergessen!):
    1. deine Lösung
    2. etwas umständliche C++-Lösung von mir (die aber trotzdem besser sein könnte als das bisherige)
    3. Quick&Dirty C-Lösung (inspiriert von Wutz aus anderem Thread. Vermutlich die schnellste Lösung)
    4. etwas umständliche grep-Lösung

    (Man beachte, dass die Programme jeweils leicht unterschiedliche Ausgaben haben. Ich bin nicht 100% sicher, was die Aufgabe ist. Ich habe jeweils eine mir sinnvoll erscheinende Lösung gewählt)

    Codes:
    1. hast du selber
    2.

    #include <string>
    #include <fstream>
    #include <iterator>
    #include <tuple>
    #include <cstdlib>
    #include <iostream>
    
    using namespace std;
    
    double parse_fs(const string &data, size_t pos)
    {
      return strtod(data.c_str() + pos, 0);
    }
    
    tuple<double, double> parse_coord(const string &data, size_t pos)
    {
      double x = strtod(data.c_str() + pos, 0);
      size_t after_comma = data.find(',', pos) + 1;
      double y = strtod(data.c_str() + after_comma, 0);
      return make_tuple(x,y);
    }
    
    int main()
    {
      ifstream file("test.dat");
      string data(istreambuf_iterator<char>(file.rdbuf()), istreambuf_iterator<char>());
    
      const string what_fs = "Fieldstrength : ";
      const string what_coord = "Coord:(";
    
      size_t fs_pos = data.find(what_fs);
      size_t coord_pos = data.find(what_coord);  
      if (fs_pos != string::npos) cout << "Fieldstrength : " << parse_fs(data, fs_pos + what_fs.length()) << '\n';
      if (coord_pos != string::npos) 
        {
          double x, y;
          tie(x,y) =  parse_coord(data, coord_pos + what_coord.length());
          cout << "Coord x: " << x << "\nCoord y: " << y << '\n';
        }
    }
    

    Falls du kein C++11 hast, lass die Tupel eben weg.
    3.

    #include <stdio.h>
    
    int main()
    {
      FILE *file = fopen("test.dat", "r");
      int c;
      while ((c = fgetc(file)) != EOF)
        {
          double fs, x, y;
          if (c == 'F' && 1 == fscanf(file, "ieldstrength : %lf", &fs))
            printf("Fieldstrength: %f\n", fs);
          if (c == 'C' && 2 == fscanf(file, "oord:(%lf,%lf", &x, &y))
            printf("Coord x: %f\nCoord y: %f\n", x, y);
        }
    }
    
    FS=`grep -o -m1 "Fieldstrength : [0-9]*" $1 | cut -d' ' -f3`
    XY_STRING=`grep -o -m1 "Coord:([0-9]*,[0-9]*)" $1`
    X=`echo $XY_STRING | cut -d'(' -f2 | cut -d',' -f1`
    Y=`echo $XY_STRING | cut -d',' -f2 | cut -d')' -f1`
    echo $X, $Y, $FS
    

  • Mod

    Falls du kein C++11 hast, lass die Tupel eben weg.

    Wieso nicht gleich pair ?
    Und strtod ist auch C++11.
    Edit: Nein, strtod nicht.


  • Mod

    Arcoth schrieb:

    Falls du kein C++11 hast, lass die Tupel eben weg.

    Wieso nicht gleich pair ?

    Weil tuple das bessere pair ist, sofern man tuple zur Verfügung hat.



  • Mir ist bewusst, dass ich der wahrscheinlich schlechteste Programmierer der Welt bin. Der Fakt ist aber,dass es darum nicht geht.
    Bei meiner Anwendung spielen weder Zeit, noch Effizienz eine Rolle.
    Es geht nur darum, die Werte auszulesen.

    Ich bin auch kein gelernter Programmierer o.ä.. Das bedeutet auch, dass ich nichtmal beurteilen kann wie schlecht mein Algorithmus ist.

    Fakt ist, dass ich euch und diesem Forum sehr sehr dankbar bin für die Unterstützung.

    Macht weiter so...

    Viele Grüße


Anmelden zum Antworten