Fwrite si posiziona alla fine in un file binario [c]

di il
12 risposte

Fwrite si posiziona alla fine in un file binario [c]

Ciao,
sono nuovo nel forum e anche nella programmazione.

Sto svolgendo un esercizio per imparare a usare i file binari col Mac usando xcode.
In particolare, mentre leggo una sequenza di interi, dovrei leggerne uno, moltiplicarlo per 2, e sovrascrivere il risultato al posto dell'intero successivo:
while(fread(&x,sizeof(int),1,p)==1)
{
y=x*2;
fwrite(&y,sizeof(int),1,p);
}

Tuttavia, quando visualizzo il file con la readf, scopro que il programma ha preso il primo intero, l'ha raddoppiato e l'ha aggiunto in coda al file. Ovviamente il programma esce dal ciclo e termina.

La dispensa universitaria dalla quale ho preso l'esercizio (ho copiato l'intero codice ma anche così si comporta allo stesso modo), dice che la funzione fread posiziona la testina nella posizione di memoria successiva, e fwrite scrive in quella esatta posizione. Invece fwrite, nel mio programma, si posiziona alla fine del file.

Dove sbaglio? Mi sono spiegato male?

PS Il file prova.txt è stato creato con "wb", la lettura/scrittura con "r+b".

Grazie

12 Risposte

  • Re: Fwrite si posiziona alla fine in un file binario [c]

    Posto un file con una quantità pari di numeri interi, questo codice:
    #include <stdio.h>
    #include <stdlib.h>
    
    
    int main() {
    
    	FILE *fl;
    	int i;
    	int *ptr;
    
    	ptr = malloc(sizeof(int));
    	
    	fl = fopen("/percorso/del/file", "r+");
    
    	while (fread(ptr, sizeof(int), 1, fl)==1) {
    		i = *ptr * 2;
    		fwrite(&i, sizeof(int), 1, fl);
    	}
    
    	fclose(fl);
    
    	return (0);
    
    }
    funziona come tu richiedi.
  • Re: Fwrite si posiziona alla fine in un file binario [c]

    Vuott, grazie mille per la risposta, purtroppo però il risultato non cambia.
    Allora, ho modificato leggermente il tuo codice così:
    1) ho aggiunto all'inizio la creazione di un file binario con un ciclo for, immettendo i numeri interi da 1 a 4 e salvandoli nel file bin.txt.
    2) ho aggiunto alla fine la lettura e stampa del file per visualizzarne il nuovo contenuto:
    #include <stdio.h>
    #include <stdlib.h>
    
    int main() {
        
        FILE *fl;
        int i;
        int a;
        int *ptr;
        
        // CREO FILE
        fl=fopen("bin.txt","wb");
       
        for (i=1;i<=4;i++)
            fwrite(&i,sizeof(int),1,fl);
        fclose(fl);
        
        // ELABORO 
        ptr = malloc(sizeof(int));
        
        fl = fopen("bin.txt", "r+");
        
        while (fread(ptr, sizeof(int), 1, fl)==1) {
            i = *ptr * 2;
            fwrite(&i, sizeof(int), 1, fl);
        }
        
        fclose(fl);
        
        //STAMPO
        fl=fopen("bin.txt","r");
        while(fread(&a,sizeof(int),1,fl)==1)
            printf("\n%d",a);
            
        fclose(fl);
       
        return (0);  
    }
    risultato:
    file iniziale:
    1
    2
    3
    4
    file finale:
    1
    2
    3
    4
    2

    fwrite è andato ancora a scrivere alla fine del file e non nel byte immediatamente successivo alle lettura.
    Il file è illeggibile aprendolo come file di testo quindi penso di averlo creato correttamente come file binario.
  • Re: Fwrite si posiziona alla fine in un file binario [c]

    Se il file originale è

    1
    2
    3
    4

    cosa dovrà contenere quello finale?
  • Re: Fwrite si posiziona alla fine in un file binario [c]

    1
    2
    3
    6

    dovrebbe leggere il primo numero (1) e posizionarsi sul secondo
    sovrascrivere sul secondo numero il primo numero raddoppiato (1*2=2) e posizionarsi sul terzo
    leggere il terzo (3) e posizionarsi sul quarto
    sovrascrivere sul quarto numero il numero raddoppiato (3*2=6)

    la versione con solo 4 numeri è per occupare poco spazio nel forum con l'esempio diretto.

    Invece il programma:

    legge il primo numero (1) e si posiziona sul secondo
    invece di adempiere il comando write in questa posizione scrive il numero raddoppiato (1*2=2) in coda al file:

    1
    2
    3
    4
    2
  • Re: Fwrite si posiziona alla fine in un file binario [c]

    Quando si legge e scrive un file binario (a proposito, manca la b finale nelle open), ovvero quando si usa il file binario in update, è necessario indicare che si sta cambiando il tipo di operazione che si sta facendo tramite una fseek.

    Ovvero, nel ciclo while dove hai messo la

    fread ...

    prima della fwrite va una

    fseek(fl, 0, SEEK_CUR);

    e dopo la fwrite, prima di tornare alla fread, un'altra

    fseek(fl, 0, SEEK_CUR);

    Fra l'altro non ha senso usare la malloc e il puntatore (ptr). Puoi utilizzare la variabile a così come hai fatto alla fine, ovvero
    
        // ELABORO 
        fl = fopen("bin.txt", "r+b");
        
        while (fread(&a, sizeof(int), 1, fl)==1) {
            i = a * 2;
    
            fseek(fl, 0, SEEK_CUR);
            fwrite(&i, sizeof(int), 1, fl);
            fseek(fl, 0, SEEK_CUR);
        }
        
        fclose(fl);
    
  • Re: Fwrite si posiziona alla fine in un file binario [c]

    Ho riprovato il mio codice, e devo dire che a me funziona perfettamente.

    Infatti, posto un file formato dai seguenti dati:
    01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00

    ottengo coerentemente questo risultato:
    01 00 00 00 02 00 00 00 03 00 00 00 06 00 00 00
  • Re: Fwrite si posiziona alla fine in un file binario [c]

    OREGON:
    grazie mille con il seek funziona correttamente e mi dà il risultato voluto!

    VUOTT: non capisco bene i dati che hai posto, perchè ci sono quegli zeri? Vedo all'interno le sequenze corrette come da te evidenziato ma non capisco gli zeri.

    PER ENTRAMBI:

    trovato il modo di operare con l'utilizzo di seek, mi rimane il dubbio amletico sul perchè la versione di vuott non funziona sul mio computer. Potrei far finta di niente e fregarmene ma è un atteggiamento poco... informatico hehe. Per chi volesse cimentarsi nell'enigma...

    Aggiungo che l'esercizio l'ho preso da questa dispensa universitaria:

    dove si stabilisce che il codice con il solo write senza seek, dovrebbe funzionare (così come funziona a vuott).

    Comunque sia grazie ancora a Oregon e Vuott per le risposte!
  • Re: Fwrite si posiziona alla fine in un file binario [c]

    karletto ha scritto:


    ma non capisco gli zeri.
    Perché ogni valore di tipo Intero (int) occupa 32 bit di memoria, quindi 4 byte.
    La disposizione inoltre dei byte di ciascun valore - almeno nel mio sistema - è in little-endian.

    karletto ha scritto:


    dove si stabilisce che il codice con il solo write senza seek, dovrebbe funzionare (così come funziona a vuott).
    Infatti sia la funzione fread( ) sia la funzione fwrite( ) spostano ciascuna il puntatore interno del file avanti di 4 byte, rendendo così superfluo il fseek( ) .
  • Re: Fwrite si posiziona alla fine in un file binario [c]

    Vuott, e te li visualizza così a video? O dai delle istruzioni particolari?

    se fwrite nel mio caso non si ferma nella posizione dovuta ma si reca in fondo al file, potrebbe essere un problema di xcode o del Mac? Nel senso che magari anche se creo (credo di creare) un file binario, c'è qualcosa di diverso che non posso sapere per ignoranza e inesperienza. Posso sopravvivere anche usando un fwrite tarpato ma preferirei capire perchè sul mio computer non funziona. e sugli altri sì.

    Grazie a chiunque abbia un illuminazione a tal proposito.
  • Re: Fwrite si posiziona alla fine in un file binario [c]

    Vedi in

    http://www.cplusplus.com/reference/cstdio/fseek
    On streams open for update (read+write), a call to fseek allows to switch between reading and writing.

    e

    http://stackoverflow.com/questions/1713819/why-fseek-or-fflush-is-always-required-between-reading-and-writing-in-the-read-w
    why fseek or fflush is always required between reading and writing in the read/write “+” modes

    I buffer di I/O interni sono comunque separati e i puntatori r e w sono due distinti.
  • Re: Fwrite si posiziona alla fine in un file binario [c]

    Grazie dei link, non posso dire di aver capito moltissimo, ma credo che si dica che fseek (fflush che ancora non conosco) sono obbligatori in casi come questo.
    Ma rimane inspiegato il perchè vuott non necessita di seek.
    L'unica spiegazione che mi do è che in qualche modo il mio sistema (el capitan + xcode) non è compatibile con l'utilizzo di fwrite dopo fread.
    Per il momento tengo buona questa.
  • Re: Fwrite si posiziona alla fine in un file binario [c]

    karletto ha scritto:


    Vuott, e te li visualizza così a video? O dai delle istruzioni particolari?
    Dopo aver lanciato il codice, io vado a verificare semplicemente il contenuto del file mediante un editor esadecimale.


    karletto ha scritto:


    ... ma credo che si dica che fseek (fflush che ancora non conosco) sono obbligatori in casi come questo.
    Ma rimane inspiegato il perchè vuott non necessita di seek.
    ...evidentemente è molto consigliabile, ma non necessario.
Devi accedere o registrarti per scrivere nel forum
12 risposte