Problem beim Abspeichern in Datei



  • --- Ja, vermutlich hast du recht.



  • Ich werde daraus einfach nicht schlau...

    Wenn es euch passt, möchte ich nochmals ganz von vorne beginnen.

    1. Ich erstelle eine Binärdatei in die ich eine gewisse Anzahl an double Werten eintrage:

    double zahl1 = 1;
    	double zahl2 = 2;
    	double zahl3 = 3;
    	double zahl4 = 4;
    
    	pSave = fopen(argv[1], "wb");
    
    	if(pSave != NULL)
    	{
    		fwrite(&zahl1, sizeof(double), 1, pSave);
    		fwrite(&zahl2, sizeof(double), 1, pSave);
    		fwrite(&zahl3, sizeof(double), 1, pSave);
    		fwrite(&zahl4, sizeof(double), 1, pSave);
    		fclose(pSave);
    	}
    

    2. Ich lese die Daten aus der Binärdatei aus:

    pRead = fopen(argv[1], "rb");
    
    	char* buff = buffer;
    
    	if(pRead != NULL)
    	{
    		while(!feof(pRead))
    		{
    			fread(&buff, sizeof(double), 1, pRead);
    			buff++;
    //Doch warum sollte ich gleichzeitig Lesen und Schreiben?
    
    		}
    
    		fclose(pRead);
    	}
    

    3. Dateiendung ändern:

    for(int i = 0, buffer[i] != '\0', i++)
    	{
    		if(buffer[i] == '.')
    		{
    			buffer[i+1] = 't';
    			buffer[i+2] = 'x';
    			buffer[i+3] = 't';
    		}
    	}
    

    4. Anschließend in diese txt Datei schreiben:

    pSave = fopen(argv[1], "w");
    
    	if(pSave != NULL)
    	{
    		fprintf(pSave, "%s\n", buffer); //Wie oft wird geschrieben? Der buff pointer zählt hoch...
    
    		fclose(pSave);
    	}
    

  • Mod

    Wenn du Schwierigkeiten hast, den Gesamtablauf zusammenzusetzen, dann teil das Problem doch mal in Unterfunktionen mit klar abgegrenzten Aufgaben auf. Schreibe folgende Funktionen:

    void binaeres_schreiben(double *array, unsigned int N, FILE *datei);
    // Schreibt N doubles aus array binär in datei
    
    unsigned int binaeres_lesen(double* array, FILE *datei);
    // Liest doubles im Binärformat aus datei in array ein. Gibt die Anzahl der gelesenen Elemente zurück
    
    void my_strcat(char *ziel, const char* quelle);
    // Fügt die Zeichenkette quelle hinten an die Zeichenkette ziel an. ziel muss groß genug für das Ergebnis sein.
    
    void normales_schreiben(double *array, unsigned int N, FILE *datei);
    // Schreibt N doubles aus array in menschenlesbarer Form in datei. Einzelne Werte werden durch Zeilenumbrüche getrennt.
    

    Jede Unterfunktion sollte für dich leicht zu schreiben sein. Und es sollte nicht schwer sein, mit diesen Funktionen ein Hauptprogramm zu schreiben.

    P.S.: Und der von mir gewählte Funktionsname my_strcat ist ein Wink mit dem Zaunpfahl.



  • Nochmal zur Aufgabe:
    In einer Binär-Datei sind eine gewisse Anzahl von double Werten gespeichert. Schreibe ein Programm das:
    a) alle Werte einliest und als Text in eine Textdatei schreibt. Jeder Wert soll in einer eigenen Zeile stehen.
    b) Am Ende soll das Programm außerdem den Durchschnitt aller eingelesenen Zahlen am Bildschirm ausgeben.
    c) Der Name der zu lesenden Datei wird als Kommandozeilen-Parameter übergeben. Der Name der Ausgabedatei soll im Programm automatisch erstellt werden indem die Dateierweiterung durch txt ersetzt wird. Beispiel: "werte.bin" ! "werte.txt".

    a) Du kannst alle Werte erst einlesen und dann in die Textzdatei speichern. Dafür musst du aber vorher wissen wieviel Zahlen du hast.
    Dafür brauchst du dann aber ein Array von double
    Besser: Du liest ein Wert ein und speicherst ihn gleich in der Textdatei. Dann ist egal wie viele Daten du hast.

    b) Dafür brauchst du die Summe der Zahlen und die Anzahl. Du musst also mit den double-Werten rechnen. Darum brauchst du double-Variablen.

    c) hast du schon 🙂

    Zu 2.

    char* buff = buffer;
    
        if(pRead != NULL)
        {
            while(!feof(pRead))
            {
                fread(&buff, sizeof(double), 1, pRead);  // Hier list du 8 Byte an die Stelle von buff (8 = sizeof(double))
                buff++;                                  // Hier erhöhst du buff um 1 Byte, da buff ein char* ist.
    //Du überschreibst als immer fleißig deine Werte.
    

    Zu 4.

    fprintf(pSave, "%s\n", buffer); //Wie oft wird geschrieben? Der buff pointer zählt hoch...
    

    In buffer (wenn es richtig gemacht wäre) stehen noch Binörwerte. In die Textdatei sollen aber (ASCII-)Zeichen.
    Das wird mit printf("%f") gemacht. Und wegen " ... in einer eigenen Zeile .." ein "%f\n"



  • Irgendwie komme ich jetzt noch mehr durcheinander, als ich es zuvor schon war.

    Die Funktionen sehen bei mir jetzt folgendermaßen aus:

    void binaeres_schreiben(double *array,FILE *datei)
    {
    	int i;
    
    	if(datei != NULL)
    	{
    		for(i = 0; i < N; i++)
    		{
    			fwrite(&array, sizeof(double), 1, datei);
    		}
    	}
    }
    
    unsigned int binaeres_lesen(double* array, FILE *datei)
    {
    	int i;
    	int anz;
    
    	if(datei != NULL)
    	{
    		while(!feof(datei))
    		{
    			anz = fread(&array,sizeof(double), 1, datei);
    
    			if(anz == 0);
    			{
    				break;
    			}
    		}
    
    		return anz; //falsch - ich weiß
    	}
    }
    
    void endung(double* array)
    {
    	for(int i = 0; array[i] != '\0'; i++) 
         { 
             if(array[i] == '.') 
             { 
                 array[i+1] = 't'; 
                 array[i+2] = 'x'; 
                 array[i+3] = 't'; 
             } 
         }
    }
    
    void normales_schreiben(double *array, FILE *datei)
    {
    	int i;
    
    	for(i = 0; i < N; i++)
    	{
    		fprintf(datei, "%f\n", array[i]);
    	}
    }
    

    Um die Anzahl zu ermitteln, muss ich mir noch den Wert zwischenspeicher, bevor der pointer wieder erhöht wird, nur bekomme ich immer Konvertierungsfehler.



  • fread() gibt die Anzahl der gelesenen Zeichen/Bytes zurück.
    Für dich ist doch aber die Anzahl der gelesenen double-Werte wichtig.

    Nebenbei ist array doch schon ein Zeiger auf das Feld. Da darfst du dann keinen Adressoperator (&) mehr nehmen 😮

    Und das N gehört in die Parameterliste. Nix mit globalen Variablen. 😡


  • Mod

    Zusätzlich zu dem was DirkB gesagt hat:
    Beim binären Schreiben, schreibst du immer den gleichen Wert. Weißt du uberhaupt, was der dritte Parameter von fwrite macht?

    Anzahl beim Lesen: Zähl doch mit!

    Endung anfügen: Da hatte ich die Aufgabenstellung nicht gelesen. Ein Zusammenfügen von Zeichenketten war gar nicht gefragt. Die Ersetzung sollte so an sich ok sein. Aber der Parameter der Funktion stimmt überhaupt nicht. Merh Sorgfalt beim Programmieren und weniger Copy&Paste!

    Und damit dir alles klarer wird, versuch mal ein Hauptprogramm mit den Funktionen zu schreiben, egal ob sie schon vollständig funktionieren oder nicht. Fehler kannst du mit dieser Aufteilung recht gut isolieren und aufspüren.



  • SeppJ schrieb:

    Zusätzlich zu dem was DirkB gesagt hat:
    Beim binären Schreiben, schreibst du immer den gleichen Wert. Weißt du uberhaupt, was der dritte Parameter von fwrite macht?

    Anzahl beim Lesen: Zähl doch mit!

    Endung anfügen: Da hatte ich die Aufgabenstellung nicht gelesen. Ein Zusammenfügen von Zeichenketten war gar nicht gefragt. Die Ersetzung sollte so an sich ok sein. Aber der Parameter der Funktion stimmt überhaupt nicht. Merh Sorgfalt beim Programmieren und weniger Copy&Paste!

    Und damit dir alles klarer wird, versuch mal ein Hauptprogramm mit den Funktionen zu schreiben, egal ob sie schon vollständig funktionieren oder nicht. Fehler kannst du mit dieser Aufteilung recht gut isolieren und aufspüren.

    Nun dieser gibt die Anzahl der zu schreibende Elemente an:

    unsigned int binaeres_lesen(double* array, FILE *datei)
    {
    	int anz;
    	int zaehler = 0;
    
    	if(datei != NULL)
    	{
    		while(!feof(datei))
    		{
    			anz = fread(array,sizeof(double), 1, datei);
    
    			if(anz == 0)
    			{
    				break;
    			}
    
    			zaehler++;
    		}
    
    		return zaehler;
    	}
    }
    

    Müsste doch eigentlich so passen, da ja bis zum Dateiende durchlaufen wird.

    Auch hier habe ich wieder Schwierigkeiten, denn welche Parameter würden sonst in Frage kommen? Aber an diesem Beispiel sieht man perfekt, dass es mir einfach schwer fehlt einzelne Aufgaben miteinander zu verknüpfen.

    Das Programm ist fertig (ich habe nur die einzelnen Fkt. gepostet), jedoch erhalte ich jedesmal ein Debug Assertion Failed. Anscheinend funktioniert in Zeile 54 (bei mir) ein fopen nicht, komischerweise befindet sich in dieser Zeile aber keines.



  • Woher sollen wir wissen in welcher deiner Quelltextfassungen der Fehler in Zeile 54 angezeigt wird. Es kann auch sein das die Ursache für die Fehlermeldung ein paar Zeilen früher liegt.

    Und, wenn noch ein Fehler auf Grund des Quelltextes angezeigt wird ist ein Programm noch nicht fertig ⚠



  • DirkB schrieb:

    fread() gibt die Anzahl der gelesenen Zeichen/Bytes zurück.

    Das ist falsch.
    fread gibt die Anzahl der erfolgreich gelesenen Blöcke (von Zeichen/Bytes/...) zurück.



  • MichaelE schrieb:

    Aber an diesem Beispiel sieht man perfekt, dass es mir einfach schwer fehlt einzelne Aufgaben miteinander zu verknüpfen.

    Wenn es dir trotz vieler Versuche immer noch so schwer fällt, zu abstrahieren und dir einen "globaleren" Überblick über dein Programm zu verschaffen, solltest du vielleicht mal nach einem anderen Job Ausschau halten.

    SeppJ schrieb:

    Und damit dir alles klarer wird, versuch mal ein Hauptprogramm mit den Funktionen zu schreiben, egal ob sie schon vollständig funktionieren oder nicht. Fehler kannst du mit dieser Aufteilung recht gut isolieren und aufspüren.

    Übersichtlicher (und damit einfacher zu begreifen, auch noch nach längerer Zeit) ist es, Funktionalitäten zu separieren und in Funktionen zu kapseln. Auch die Fehlersuche wird dann viel einfacher, da du die Funktion in der der Fehler auftritt, einfacher ermitteln kannst. Sowas nennt man auch Top-Down Entwurf, also z.B.

    int main()
    {
      int anzahl;
      char *datei = "bla.bin";
      char *zieldatei[FILENAME_MAX];
    
      fehlerbehandlung( datei );
      ermittleZieldateiname( zieldatei, datei );
      anzahl = kopiere( datei, zieldatei );
    
      printf("%d Werte wurden kopiert.",anzahl );
      return 0;
    }
    
    void fehlerbehandlung( const char *name ) { /* hier dann konkret implementieren */ }
    ...
    void ermittleZieldateiname( char *zname, const char *name ) { /* hier dann konkret implementieren */ }
    ...
    


  • DirkB schrieb:

    was falsches über fread()

    Ups. 🙄

    Danke für die Richtigstellung.



  • Zur Ergänzung: Programm funktioniert nun endlich so wie es soll 🙂



  • Bei diesem Programm bekomme ich einen Zugriffsverletzung beim Schreiben, wenn ich das Programm starte, jedoch kann ich den FEhler nicht ausfindig machen..

    typedef struct
    {
    	char name[31];
    	int alter;
    }Person;
    
    int main()
    {
    	FILE *pRead;
    	FILE *pSave;
    	int anzahl = 0;
    
    	Person per;
    
    	pRead = fopen("Struktur.txt", "r");
    	pSave = fopen("PERSONEN1.BIN", "wb");
    
    	if(pRead == NULL)
    	{
    		printf("Fehler");
    		return 0;
    	}
    
    	if(pSave == NULL)
    	{
    		printf("Fehler");
    		return 0;
    	}
    
    	while(!feof(pRead))
    	{
    		fscanf(pRead, "%s", per.name);
    		fscanf(pRead, "%d", per.alter);
    		fwrite(&per.name, sizeof(per.name), 1, pSave);
    		fwrite(&per.alter, sizeof(per.alter), 1, pSave);
    
    		anzahl++;
    	}
    
    	printf("Anzahl: %d", anzahl);
    
    	fclose(pRead);
    	fclose(pSave);
    

  • Mod

    Es macht doch immer wieder Freude, wenn man sieht, dass drei Seiten gut gemeinter Hilfe zu sichtbaren Verbesserungen und Erfolgen führen [/ironie]

    Zum Fehler: Compilier mal mit Warnungen. So wie du es immer tun solltest.



  • DirkB * schrieb:

    Nebenbei ist name doch schon ein Zeiger. Da darfst du dann keinen Adressoperator (&) mehr nehmen 😮

    * Sinngemäß am 18:26:01 06.09.2011



  • http://www.cplusplus.com/reference/clibrary/cstdio/fwrite/

    Durchlesen und schauen was du anders in deinen Quelltexten machst 👍


Anmelden zum Antworten