Bis zum Ende einer Datei lesen und dann stoppen



  • Hey,

    ich habe so meine Probleme mit der fread und fwrite Funktion. Und zwar möchte ich aus einer .dat Datei jpgs wiederherstellen. Dies möchte ich mit einer while loop bewerkstelligen in der ich jedes mal 512 bytes in einen buffer einlese und dann checke ob die ersten 4 bytes gleich dem header von jpgs sind. Wenn ja wird eine neue Datei erstellt und gelesen und geschrieben bis ich wieder eine neue jpg finde. Dann soll die Datei geschlossen werden und eine neue aufgemacht. Mein Problem ist im Moment das ich nicht genau verstehe wie ich meine while loop beende. Ich habe gelesen das !feof(card)nicht optimal ist. Daher starte ich meine while loop so:

    while(fread(buffer, sizeof(BYTE), 512, card) != 0)

    Mein Verständnis sagt mir, das in jeder iteration 512 bytes aus card in den buffer gelesen werden. Sobald fread aber 0 zurückgibt beendet sich die while loop. Fungiert diese Bedingung hierbei nur als Test, oder liest sie auch wirklich aus sodass der filepointer in der card Datei weitergeht? Ansonsten müsste ich in die while loop ja noch einmal dasselbe statement integrieren.

    Wäre dankbar über einen Tip.

    Grüße,
    René



  • Dein fread versucht in jedem Schleifendurchlauf 512 * sizeof(BYTE) Byte nach buffer zu lesen. fread gibt die Anzahl der tatsächlich gelesenen Bytes zurück. D.h., sobald fread etwas anderes als 512 * sizeof(BYTE) liefert, ist entweder ein Lesefehler aufgetreten, oder das Dateiende erreicht worden.
    Wahrscheinlich wäre die Abbruchbedingung besser
    ... == 512 * sizeof(BYTE)
    anstatt
    ... != 0

    edit:
    obwohl es wahrscheinlich egal ist, wenn erst mal ein Fehler aufgetreten ist, oder das Dateiende erreicht ist, sollte spätestens der nächste Aufruf 0 liefern.
    Aber konkret zu Deiner Frage nochmal:
    Ja, jeder Durchlauf liest tatsächlich in buffer und vergleicht dann die Anzahl der gelesenen Bytes mit 0.



  • Vielen Dank Belli,

    also hab ich in der while Loop dann die ersten 512 bytes zur Verfügung und muss nicht noch einmal in der Loop in den Buffer lesen? Baue ich in die while loop nun ein fwrite statement ein, so wird der Inhalt einmal geschrieben, baue ich fwrite 2 mal ein, so würde der Buffer 2 mal geschrieben werden? Nur fürs Verständnis. In meinem Code habe ich nen schönen Segmentation Fault und bin bisher nocht nicht drauf gekommen.



  • Belli schrieb:

    Wahrscheinlich wäre die Abbruchbedingung besser
    ... == 512 * sizeof(BYTE)

    Die Abbruchbedingung selbst muss hier natürlich

    ... != 512
    

    heißen, weil fread die Anzahl der gelesenen Blöcke rückgibt, also üblicherweise so

    size_t gelesen;
    while( gelesen=fread(buffer, sizeof(BYTE), 512, card) )
    {
      if( gelesen==512 )
      {
        ...  /* vollständig gelesener Block */
      }
      else
      {
        ...  /* nicht vollständig gelesener Block ( letzter Block vor Dateiende oder vor Lesefehler ) */
      }
    }
    


  • Storms schrieb:

    also hab ich in der while Loop dann die ersten 512 bytes zur Verfügung

    Nur beim ersten Mal. Beim zweiten Durchlauf hast Du die zweiten 512 Byte der Datei usw.



  • Wutz schrieb:

    Belli schrieb:

    Wahrscheinlich wäre die Abbruchbedingung besser
    ... == 512 * sizeof(BYTE)

    Die Abbruchbedingung selbst muss hier natürlich

    ... != 512
    

    heißen, weil fread die Anzahl der gelesenen Blöcke rückgibt, also üblicherweise so

    size_t gelesen;
    while( gelesen=fread(buffer, sizeof(BYTE), 512, card) )
    {
      if( gelesen==512 )
      {
        ...  /* vollständig gelesener Block */
      }
      else
      {
        ...  /* nicht vollständig gelesener Block ( letzter Block vor Dateiende oder vor Lesefehler ) */
      }
    }
    

    Das verstehe ich nicht so ganz. Solange der Buffer 512 Blöcke liest soll die while Funktion laufen, und sobald es weniger sind soll sie stoppen. Also müsste while(fread(buffer, sizeof(BYTE), 512, card) == 512 * sizeof(BYTE)) doch richtig sein?

    Übrigens bekomme ich einen Segmentation Fault, und der buffer ist irgendwie auch leer wenn ich ihn mir mit GDB anzeigen lasse nach der ersten iteration.

    Sagt euch die backtrace Meldung etwas?

    #0 0xb7e58430 in _IO_fwrite (buf=0xbfffef90, size=1, count=512, fp=0xbffff018) at iofwrite.c:43
    #1 0x080488f4 in main () at recover.c:89



  • Storms schrieb:

    Das verstehe ich nicht so ganz. Solange der Buffer 512 Blöcke liest soll die while Funktion laufen, und sobald es weniger sind soll sie stoppen.

    Guck mal hier http://www.cplusplus.com/reference/cstdio/fread/
    Da findest du u. a. die Deklaration von fread:

    size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );

    Die Funktion liefert die Anzahl der eingelesenen Elemente, wobei jedes Element die Größe size hat.

    Storms schrieb:

    Also müsste while(fread(buffer, sizeof(BYTE), 512, card) == 512 * sizeof(BYTE)) doch richtig sein?

    Das kann nur klappen, wenn 1 == sizeof(BYTE) ist (was in deinem Fall wohl zufällig der Fall sein dürfte).
    Du weißt aber so der so nicht wie viele Bytes beim letzten fread gelesen wurden,
    also schreibst du besser:

    while((gelesen=fread(buffer, sizeof(BYTE), 512, card)) == 512)...
    

    wobei die 512 besser in einer Variable oder als Makro definiert sein sollte, weil hart gecodete Werte pfui sind.

    Storms schrieb:

    Übrigens bekomme ich einen Segmentation Fault, und der buffer ist irgendwie auch leer wenn ich ihn mir mit GDB anzeigen lasse nach der ersten iteration.

    Zeig doch mal die Deklaration von buffer und von card.



  • Da wir nicht wissen ob buffer richtig deklariert ist würde ich hier die Abstuzursache vermuten.

    die Beiden Parameter size und count geben die Blockgrösse und die maximale Anzahl der Blöcke an.
    Je nachdem wie man die Parameter nutzt bekommt man entweder die Anzahl der Blöcke
    oder z.B. die Anzahl gelesener Bytes.

    Wenn fread weniger gelesen hat als erwartet ist entweder die Datei zu Ende oder
    es ist ein Fehler aufgetreten. Fehlerusache siehe feof() oder ferror().

    EDIT: zu spät 🙂



  • Danke euch beiden. Zum Hintergrund. Ich habe gerade erst mit C angefangen und mache einen Online Kurs parallel zu meinem Business Master im Ausland. Daher sind noch nicht ganz soviele Grundkenntnise vorhanden 😉

    Es kommt jetzt übrigens kein Segmentation Fault mehr, das Program produziert allerdings auch keine jpgs. Ich habe mal wieder GDB laufen lassen und scheinbar wird die jpg Funktion nie getriggert. Im ersten Durchlauf enthält der Buffer das folgende:

    '\000' <repeats 80 times>, "http://youtu.be/oHg5SJYRHA0", '\000' <repeats 404 times>

    Im zweiten und allen folgenden:

    '\000' <repeats 511 times>

    Meinen Buffer deklariere ich so:

    typedef uint8_t  BYTE;
    

    vor main

    BYTE buffer[512];
    

    in main

    Hier eine zwischenfrage die mir gerade eingefallen ist. Wieso eigentlich nicht 511 als Zahl? Der Buffer ist ja ein array, sollte also bei 0 starten. Oder ist am Ende jeden Buffers auch noch ein \0?

    Hier die card Deklaration:

    FILE* card = fopen("card.raw", "r");
    	if (card == NULL)
    	{
    		printf("Could not open card.raw");
    		fclose(card);
    		return 1;
    	}
    

    Danke!



  • die deklaration des buffers ist okay.

    Storms schrieb:

    Wieso eigentlich nicht 511 als Zahl?

    Geht schon, wenn du 511 BYTE-Elemente willst, dann mit einem Index von 0 bis 510.
    Bei 512 BYTE-Elementen geht der Index von 0 bis 511.
    Allgemein geht der Index eines Arrays mit n Elementen(n > 0) von 0 bis n-1.

    Storms schrieb:

    Oder ist am Ende jeden Buffers auch noch ein \0?

    Nein.



  • Alles klar, danke. Eine Idee warum mein Buffer so seltsame Sachen enthält?



  • ich habe keine ahnung was gdb ist aber ich vermute, dass
    diese seltsamen "sachen" in deiner datei card.raw stehen.



  • GDB ist ein debugger den ich unter linux benutze. Die card.raw Datei enthält jpgs, die ich wiederherstellen muss. Daher ist der Inhalt doch ein wenig komisch.



  • um zu überprüfen ob deine einlesefunktion richtig funktioniert,
    kannst du z.b. eine textdatei einlesen und den inhalt des buffers mit dem datei-inhalt vergleichen.


Anmelden zum Antworten