nach bestimmter zahl in neue Datei schreiben



  • Hallo,

    bin ein echter newbe, doch möchte ich nun einen Aufgabe lösen.
    Der Titel ist warscheinlich nicht aussagekräftig. Daher hier die Fragestellung:

    ich hab ein Programm das Werte errechnet und in eine Datei schreibt, wenn man dem Programm als Argument den Dateinamen übergibt. Nun soll aber nicht eine einzige Datei mit den Werten gefüllt werden, sondern nach einem bestimmten wiederholung eine neue Datei erstellt und gefüllt werden. Z.B. ich gebe das Tool so ein

    testtool -f Dateiname -n 100

    das Tool soll nun die Datei "Dateiname_1" erstellen und die ersten 100 Werte darin schreiben. Danach soll es die Datei "Dateiname_1" schließen und die Datei "Dateiname_2" öffnen und die nächsten 100 Werte dort ablegen usw.

    wie bewerkstellige ich dies nun??



  • du rufst nacheinander das programm auf:
    testtool -f Dateiname_1 -n 100
    testtool -f Dateiname_2 -n 200
    ich vermute mal, es wird keinen parameter geben, wo du den start ausgeben kannst.

    also wirst du danach die dateien alle wieder öffnen müssen und die ersten 100*n einträge entfernen.

    vll also auch:
    testtool -f Dateiname_temp -n 10000
    und dann die Dateiname_temp öffnen und jeweils 100 Werte lesen und in eine Datei schreiben, dann die nächste etc.

    evtl. lohnt sichs auch, nen kleinen betrachter dazu zu schreiben. der halt die ganze datei öffnet und dir ne html-seite oder iwie so was ausgibt - je nach dem, was du genau möchtest...

    bb



  • Ich glaube, ich würde die Dateinamen mit Stringstreams basteln.
    http://www.cplusplus.com/reference/iostream/ostringstream/

    char* filename=...
    ofstream out(filename);
    

    jetzt

    ostrstream longfilename;
    longfilename<<filename<<'_'<<filenumber;
    ofstream out(longfilename.str().c_str());
    


  • für mich klang das eher so, als ob er das programm nicht selbst geschrieben hätte - ist also vermutlich nicht das, was er wissen wollte.

    bb



  • unskilled: ich möchte nicht extra arbeit schaffen, jedes mal wenn ich das Programm starte. Es ist auch unklar wieviele werte das Programm erzeugt.

    volkard: momentan steht folgendes im code (hab ich von einem anderen Programm)

    if (strncmp(argv[i],"-f",2)==0)
    {
      fout.open(argv[i+1]);
      flag = 1;
    }
    
    /*hier eine Schleife die den Wert errechnet*/
    
    if (flag==1)
    {
      fout.close();
    }
    

    wie müsste ich denn Code nun ändern?

    ich wäre dir über eine recht genaue Angabe sehr sehr dankbar.

    Ich bin da sehr Neu in dem Thema und würde dies gerne später auch für meine weiteren Programme nutzen.

    :p :p :p :p



  • wh.for schrieb:

    wie müsste ich denn Code nun ändern?

    ich wäre dir über eine recht genaue Angabe sehr sehr dankbar.

    Ich bin da sehr Neu in dem Thema und würde dies gerne später auch für meine weiteren Programme nutzen.

    Hallo wh.for,

    willkommen im C++-Forum.

    wenn man etwas wieder verwenden möchte so bietet es sich u.U. an, es in eine oder mehrere Klassen zu implementieren. Du brauchst eigentlich zwei Dinge:
    1.) einen Dateinamen, den man 'hoch zählen' kann
    2.) eine 'Schreiber-Klasse', die automatisch eine neue Datei aufmacht, wenn die aktuelle Datei 'voll' ist.

    Das könnte etwa so aussehen:

    #include <fstream>
    #include <iostream>
    #include <sstream> // std::ostringstream
    #include <string>
    #include <cassert>
    
    class ZaehlenderDateiname
    {
    public:
        explicit ZaehlenderDateiname( const char* name, int nr1 = 1 )
            : m_nr( nr1 )
            , m_name( name )
        {}
        ZaehlenderDateiname& operator++() // inkrement
        {
            ++m_nr;
            return *this;
        }
        std::string get() const
        {
            std::ostringstream buf;
            // hier wird der Dateiname zusammengebaut
            buf << m_name << "_" << m_nr;
            return buf.str();
        }
    private:
        int m_nr;
        std::string m_name;
    };
    
    class Schreiber
    {
    public:
        Schreiber( const char* filename, int anzahlProDatei )
            : m_filename( filename )
            , m_zahlenZaehler( 0 )
            , m_anzahlProDatei( anzahlProDatei )
            , m_file( new std::ofstream( m_filename.get().c_str() ) )
        {
            assert( m_file->is_open() );
        }
        ~Schreiber()
        {
            delete m_file; // schließt auch die Datei
        }
    
        void schreibeZahl( int zahl )
        {
            ++m_zahlenZaehler;
            if( m_zahlenZaehler > m_anzahlProDatei )
            {
                // Datei ist voll; nächste Datei öffnen
                delete m_file; // schließt auch die bisherige Datei
    
                ++m_filename; // nächster Dateiname -> operator++
                m_file = new std::ofstream( m_filename.get().c_str() );
                m_zahlenZaehler = 1; // die Zahl 'zahl' ist die erste in der Datei
                assert( m_file->is_open() );
            }
            *m_file << zahl << "\n";
        }
    
    private:
        // --   Kopieren verhindern; wg m_file
        Schreiber( const Schreiber& );
        Schreiber& operator=( const Schreiber& );
    
        // --   member
        ZaehlenderDateiname m_filename;
        int m_zahlenZaehler; // zählt die zahlen in einer Datei
        int m_anzahlProDatei;
        std::ofstream* m_file;
    };
    
    int main( int argc, char* argv[] )
    {
        using namespace std;
        assert( argc > 2 );
        int anzahlProDatei;
        istringstream buf( argv[2] );
        buf >> anzahlProDatei;
        Schreiber schreiber( argv[1], anzahlProDatei );
        for( int zahl = 1; zahl <= 150; ++zahl )
            schreiber.schreibeZahl( zahl );
        return 0;
    }
    

    wenn Du dazu Fragen hast, so stelle sie.

    Gruß
    Werner



  • Hallo Werner:
    Danke für deine Hilfe. So wie du mir angeboten hast zu dem Code Fragen zu stellen, möchte ich dies nun nutzen.

    explicit ZaehlenderDateiname( const char* name, int nr1 = 1 )
       : m_nr( nr1 )
       , m_name( name )
    {}
    

    Hier hast du den Konstruktor mit einem „explicit“ versehen und anschließend die Variablen (ich vermute mal es sind Variablen) m_nr und m_name angehängt. Solch eine Schreibweise und Zuweisung habe ich bisher noch nie gesehen. Wie funktioniert dies.

    ZaehlenderDateiname& operator++()
    

    Beim zweiten Konstruktor ist mir „& operator++()“ unklar und wo es Verwendung findet im Programm.

    Schreiber( const char* filename, int anzahlProDatei )
       : m_filename( filename )
       , m_zahlenZaehler( 0 )
       , m_anzahlProDatei( anzahlProDatei )
       , m_file( new std::ofstream( m_filename.get().c_str() ) )
    {
       assert( m_file->is_open() );
    }
    

    In der Kasse „Schreiber“ verstehe ich „m_file(new std::ofstream(m_filename.get().c_str()))“ nicht und was „assert(m_file->is_open())“ bewirkt.

    ~Schreiber()
    {
       delete m_file; // schließt auch die Datei
    }
    

    Kommt der Destruktor beim Ende des gesamten Proramms zum Zug?

    *m_file << zahl << "\n";
    

    Was macht „*m_file<<zahl<<“\n“

    // --   Kopieren verhindern; wg m_file
        Schreiber( const Schreiber& );
        Schreiber& operator=( const Schreiber& );
    

    Hier würde ich vermuten das dies eine Schleife darstellt, hab aber absolut keine Ahnung?

    Ich hab zwar noch ein paar Fragen, möchte aber erst einmal dies Verstehen. Vielleicht verstehe ich ja den Rest dann von allein.

    Danke nochmals für deine Hilfe. 🙂



  • wh.for schrieb:

    Hallo Werner:
    Danke für deine Hilfe. So wie du mir angeboten hast zu dem Code Fragen zu stellen, möchte ich dies nun nutzen.

    Oh je, da habe ich mich ja wieder auf was eingelassen 😉
    Bevor ich anfange: Praktisch alle Deine Fragen betreffen die Syntax von C++. D.h. Du bist ein Newbee (hattest Du geschrieben), und dann ist selbst dies 'unscheinbare' Programm welches Du schreiben willst, eigentlich schon zu schwer für Dich.

    Du solltest also zunächst ein Tutorial oder ein Buch durcharbeiten, und Dich an die Beispiele halten, die dort beschrieben sind. Achte dabei auf die Qualität - da ist recht viel Schrott im Umlauf - gut sollen u.a. die Bücher von Breymann und der C++-Primer sein. Du kannst Dich hier im Forum unter [Bücher] informieren.

    wh.for schrieb:

    explicit ZaehlenderDateiname( const char* name, int nr1 = 1 )
       : m_nr( nr1 )
       , m_name( name )
    {}
    

    Hier hast du den Konstruktor mit einem „explicit“ versehen und anschließend die Variablen (ich vermute mal es sind Variablen) m_nr und m_name angehängt. Solch eine Schreibweise und Zuweisung habe ich bisher noch nie gesehen. Wie funktioniert dies.

    zwei Sachen: das 'explicit' ist ein C++-keyword welches festlegt, dass der Konstruktor nicht für eine implizite Konvertierung taugt. Wenn man das 'explicit' weglässt, so wäre z.B. dies möglich:

    ZaehlenderDateiname name = "EinName";
    

    dies könnte aber auch gar nicht erwünscht sein, und somit ein Fehler sein; deshalb das 'explicit' und der obige Ausdruck liefert einen Compile-Fehler.

    mit dem ':' beginnt dann die Initialisierungsliste, dort werden die Member der Klasse initialisiert. Suche hier im Forum nach 'Initialisierungsliste'.

    wh.for schrieb:

    ZaehlenderDateiname& operator++()
    

    Beim zweiten Konstruktor ist mir „& operator++()“ unklar und wo es Verwendung findet im Programm.

    .. hate ich mir schon gedacht, deshalb habe ich das in Zeile 55 hingeschrieben. 'ZaehlenderDateiname&' ist die Referenz auf ein Objekt der Klasse 'ZaehlenderDateiname'. Das ist hier der Returntyp der Methode 'operator++()' - und ist das gleiche als ob Du schreibst:

    int i=2;
        ++i; // <- hier wird der operator++ aufgerufen
    

    wh.for schrieb:

    Schreiber( const char* filename, int anzahlProDatei )
       : m_filename( filename )
       , m_zahlenZaehler( 0 )
       , m_anzahlProDatei( anzahlProDatei )
       , m_file( new std::ofstream( m_filename.get().c_str() ) )
    {
       assert( m_file->is_open() );
    }
    

    In der Kasse „Schreiber“ verstehe ich „m_file(new std::ofstream(m_filename.get().c_str()))“ nicht und was „assert(m_file->is_open())“ bewirkt.

    ich schreibe gern alles in eine Zeile .. 'm_file( new std::ofstream( m_filename.get().c_str() ) )' steht für:

    std::string filenameAsString m_filename.get(); // liefert den neuen Filenamen als std::string
        const char filenameAsCharPtr = filenameAsString.c_str();
        std::ofstream* filePtr = new std::ofstream( filenameAsCharPtr ); // erzeuge ein std::ofstream-Objekt auf dem Heap
        m_file( filePtr ) // Pointer im Member 'm_file' merken
    

    wh.for schrieb:

    ~Schreiber()
    {
       delete m_file; // schließt auch die Datei
    }
    

    Kommt der Destruktor beim Ende des gesamten Proramms zum Zug?

    i.A. schon vorher - in diesem Fall, wenn das Objekt 'schreiber' welches in Zeile 82 erzeugt wird, den Scope verlässt, also in Zeile 86

    wh.for schrieb:

    *m_file << zahl << "\n";
    

    Was macht „*m_file<<zahl<<“\n“

    gibt eine Zahl 'zahl' und den Text "\n" (End Of Line) auf dem std::ostream *m_file aus. Wie würdest Du eine Zahl ausgeben?

    wh.for schrieb:

    // --   Kopieren verhindern; wg m_file
        Schreiber( const Schreiber& );
        Schreiber& operator=( const Schreiber& );
    

    Hier würde ich vermuten das dies eine Schleife darstellt, hab aber absolut keine Ahnung?

    Nein, mit einer Schleife hat das nichts zu tun - ignoriere es erst mal; es stellt sicher, dass Du nicht aus Versehen die Klasse Schreiber falsch verwendest.

    Gruß
    Werner


Anmelden zum Antworten