Datei öffnen und Zeilen verschieben



  • Morgen zusammen,

    Ich möchte gerne ein File einlesen und falls "MWR154=" vorkommt, soll
    es in die zweite Zeile der selben Datei verschoben werden. Falls das gesuchte an einer anderen Stelle nochmals vorkommt, soll er diese dann nach Zeile 3 verschieben.

    Bsp.

    Das
    ist
    ein
    Beispiel
    MWR154=30
    Weiter
    MWR154=34

    Output

    Das
    MWR154=30
    MWR154=34
    ist
    ein
    Beispiel
    Weiter

    Soweit bin ich bis Dato:

    int main(int argc, char *argv[])
    {
        ifstream f;  // Datei-Handle
    
    	f.open(argv[1], ios::in); // Öffne Datei aus Parameter
        int i=0;
    	while (!f.eof())          // Solange noch Daten vorliegen
        {
            getline(f, s);        // Lese eine Zeile
    		Zeile[i]=s;
    		i++;
    	}
    
    	for (k=0; k<i; k++)
    
    	{	string::size_type loc1 = Zeile[k].find( "MWR154=", 0 );
    			if( loc1 != string::npos ) 
    			{			
    						!!!! HELP !!!!
    
    			}
    			else
    			{
    			}
    
    		}
    
        f.close();                // Datei wieder schließen
    
     return 1;
     }
    

    Wie kann ich die Zeile nun auschneiden und wieder einfügen? Stelle Quellcode --> !!!!HELP!!!!..

    Geht dies überhaupt mit ifstream ? Blicke hier nicht so ganz durch und würde mich über Vorschläge/Verbesserungstipps freuen...



  • Einfach zu verschieben ist wahrscheinlich nicht so einfach. Der Ablauf sollte sein:

    (a) Zeilenweise einlesen (abspeichern bspw. in list<string>)
    (b) Alle Einträge mit "MWR154=" am Start suchen und in der Liste verschieben (Wahrscheinlich mit einer Kombination aus list.remove und list.insert)
    (c) Zeilenweise die Datei neu schreiben

    MfG SideWinder



  • SideWinder schrieb:

    Einfach zu verschieben ist wahrscheinlich nicht so einfach. Der Ablauf sollte sein:

    (a) Zeilenweise einlesen (abspeichern bspw. in list<string>)
    (b) Alle Einträge mit "MWR154=" am Start suchen und in der Liste verschieben (Wahrscheinlich mit einer Kombination aus list.remove und list.insert)
    (c) Zeilenweise die Datei neu schreiben

    MfG SideWinder

    Ich würde eine zweite Datei aufmachen, und von der ersten entsprechend kopieren. Wenn alles gut gelaufen ist, dann löscht Du die original Datei und bennenst die neue entsprechend um. Wenn was schief geht, bleibt die original Datei erhalten.



  • Ich stimme Tachyon zu - in einer Datei in-place herumzufuhrwerken, ist immer gefährlich (was passiert bei Stromausfall?).

    Was den Algorithmus angeht: Ich denke, es wäre einfacher, die verschiedenen Zeilentypen gleich beim Einlesen in verschiedene Container zu sortieren. Ich stelle mir das etwa so vor:

    #include <algorithm>
    #include <cstdio>
    #include <deque>
    #include <fstream>
    #include <iostream>
    #include <iterator>
    #include <stdexcept>
    #include <string>
    
    #ifdef _WIN32
    #  define NOMINMAX
    #  include <windows.h>
    #else
    #  include <unistd.h>
    #endif
    
    void enforce(bool condition, std::string const &message) {
      if(!condition) throw std::runtime_error(message);
    }
    
    int main() {
      std::string first_line;
      std::deque<std::string> lines_mwr;
      std::deque<std::string> lines_other;
    
      char const *const filename_in  = "datei.txt";
    
      {
        std::ifstream in(filename_in);
        std::string line;
    
        enforce(std::getline(in, first_line), "Fehler beim Lesen der Eingabedatei");
    
        while(std::getline(in, line)) {
          if(line.compare(0, 7, "MWR154=") == 0) {
            lines_mwr  .push_back(line);
          } else {
            lines_other.push_back(line);
          }
        }
      }
    
      char filename_tmp[L_tmpnam];
    
      {
        // In Produktionscode evtl. besser auf tmpfile() zurückgreifen. Das ist zwar C,
        // schließt aber eine Race-Condition aus.
        enforce(std::tmpnam(filename_tmp) != 0, "Temporärer Dateiname konnte nicht generiert werden");
    
        std::ofstream out(filename_tmp);
    
        enforce(out, "Temporäre Datei konnte nicht erstellt werden");
    
        out << first_line << '\n';
        std::copy(lines_mwr  .begin(), lines_mwr  .end(), std::ostream_iterator<std::string>(out, "\n"));
        std::copy(lines_other.begin(), lines_other.end(), std::ostream_iterator<std::string>(out, "\n"));
      }
    
    #ifdef _WIN32
      MoveFileEx(filename_tmp, filename_in, MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
    #else
      rename    (filename_tmp, filename_in);
    #endif
    }
    


  • Luftikus schrieb:

    Ich möchte gerne ein File einlesen und falls "MWR154=" vorkommt, soll
    es in die zweite Zeile der selben Datei verschoben werden. Falls das gesuchte an einer anderen Stelle nochmals vorkommt, soll er diese dann nach Zeile 3 verschieben.

    Alles einlesen sortieren und wieder ausgeben - ist aber jeden Fall die richtige Vorgehesweise. Und beim Sortieren erledigt std::stable_sort schon alles für Dich.

    #include <algorithm> // stable_sort, copy
    #include <fstream>
    #include <iostream>
    #include <iterator> // ostream_iterator
    #include <string>
    #include <vector>
    
    struct compareStr
    {
        explicit compareStr( const std::string& prefix ) : m_prefix( prefix ) {}
        bool operator()( const std::string& a, const std::string& b ) const
        {   // 'a' ist genau dann "kleiner" als 'b', falls a das prefix enthält und b nicht.
            return a.substr( 0, m_prefix.size() ) == m_prefix
                && b.substr( 0, m_prefix.size() ) != m_prefix;
        }
    private:
        std::string m_prefix;
    };
    
    int main( int argc, char* argv[] )
    {
        using namespace std; 
        if( argc < 2 )
        {
            cerr << "Bitte Dateinamen angeben" << endl;
            return -1;
        }
        vector< string > lines;
        {   // vector 'lines' aus Datei füllen
            ifstream datei(argv[1]);
            if( !datei.is_open() )
            {
                cerr << "Datei '" << argv[1] << "' nicht gefunden" << endl;
                return -1;
            }
            for( string line; getline( datei, line ); )
                lines.push_back( line );
        }
        if( lines.size() > 1 ) // Bem.: erst ab der zweiten Zeile sortieren
            stable_sort( ++lines.begin(), lines.end(), compareStr("MWR154=") );
        {   // sortierte Zeilen wieder wegschreiben
            ofstream datei(argv[1]);
            copy( lines.begin(), lines.end(), ostream_iterator< string >( datei, "\n" ) );
        }
        return 0;
    }
    

    Gruß
    Werner



  • Danke für die guten Vorschläge...Habe mich heute früh mal Werner seiner
    guten Lösung gewidmet. Funktioniert super...Nur zum Verständnis, was ist wenn er die Zeilen an Stelle 3 der Datei schreiben soll ?

    Das ändern der If-Bedingung von 2 auf 3, bringt nicht den gewünschten Erfolg :

    if( lines.size() > 2 )
    


  • if( lines.size() > 2 )
       stable_sort( lines.begin() + 2, lines.end(), compareStr("MWR154=") );
    

    Klappt so aber nur, wenn nicht vorher (vor Zeile 3) bereits ein MWR154= auftaucht, weil die ersten zwei Zeilen jetzt so bleiben, wie sie sind, siehe Werners Kommentar: "erst ab der zweiten Zeile sortieren", der nun natürlich heißen müsste: "erst ab der dritten Zeile sortieren".



  • Luftikus schrieb:

    Habe mich heute früh mal Werner seiner guten Lösung gewidmet.

    Der Dativ ist mein Tod! 🙄



  • ...


Log in to reply