GNT sans publicité, site mobile, fonctionnalitées exclusives...

Lecture / écriture dans un fichier binaire

Le
GurneyH
Bonjour.

Je suis peu habitué à manipuler des fichiers en lecture/écriture, et
je me trouve avec un code qui produit un résultat différent suivant
qu'il est compilé et exécuté sous Ubuntu et GCC ou Windows et MingW.

#include <stdio.h>
#include <stdlib.h>

FILE *xfopen(char const *path, const char *mode)
{
FILE *fp = fopen(path, mode);
if(fp == NULL)
{
perror("xfopen ");
exit(EXIT_FAILURE);
}
return fp;
}


int read_int(FILE *fp)
{
int ret;
if(fread(&ret, sizeof(int), 1, fp) < 1)
{
fprintf(stderr, "Error: read_int");
exit(EXIT_FAILURE);
}
return ret;
}


void write_int(FILE *fp, int n)
{
if(fwrite(&n, sizeof(int), 1, fp) < 1)
{
fprintf(stderr, "Error : write_int");
exit(EXIT_FAILURE);
}
}


int main(void)
{
int i, n;
char const *filename = "test.txt";
FILE *fp = NULL;

/* write */
fp = xfopen(filename, "w");
for(i = 0; i < 3; i++)
write_int(fp, i);
fclose(fp); /* 1 2 3 */

/* read / write */
fp = xfopen(filename, "rb+");
n = read_int(fp);
printf("n = %d", n);
write_int(fp, n + 10);
fclose(fp); /* 1 11 3 */

/* read */
fp = xfopen(filename, "r");
for(i = 0; i < 3; i++)
printf("%d", read_int(fp));
fclose(fp);

return 0;
}

Je commence par écrire 3 entiers dans un fichier.
J'ouvre une deuxième fois le fichier en mode rb+, je lis le premier
entier, et j'écris à la suite.

Problème, sous Ubuntu, cette écriture fonctionne bien, et l'affichage
du contenu du fichier me donne bien 1, 11, 3, qui est le résultat
attendu.
Sous Windows par contre, le fichier contient toujours 1, 2, 3.

J'ai fait quelques tests avec ftell entre la lecture et l'écriture, et
la valeur retournée est normale(la taille d'un entier).

Une explication?

Merci d'avance.
Lire les 16 réponses

Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses Page 1 / 4
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
GurneyH
Le #22860261
On 29 nov, 10:14, GurneyH
Bonjour.

Je suis peu habitué à manipuler des fichiers en lecture/écriture, e t
je me trouve avec un code qui produit un résultat différent suivant
qu'il est compilé et exécuté sous Ubuntu et GCC ou Windows et MingW .

#include #include
FILE *xfopen(char const *path, const char *mode)
{
    FILE *fp = fopen(path, mode);
    if(fp == NULL)
    {
        perror("xfopen ");
        exit(EXIT_FAILURE);
    }
    return fp;

}

int read_int(FILE *fp)
{
    int ret;
    if(fread(&ret, sizeof(int), 1, fp) < 1)
    {
        fprintf(stderr, "Error: read_int");
        exit(EXIT_FAILURE);
    }
    return ret;

}

void write_int(FILE *fp, int n)
{
    if(fwrite(&n, sizeof(int), 1, fp) < 1)
    {
        fprintf(stderr, "Error :  write_int");
        exit(EXIT_FAILURE);
    }

}

int main(void)
{
    int i, n;
    char const *filename = "test.txt";
    FILE *fp = NULL;

    /* write */
    fp = xfopen(filename, "w");
    for(i = 0; i < 3; i++)
        write_int(fp, i);
    fclose(fp); /* 1 2 3 */

    /* read / write */
    fp = xfopen(filename, "rb+");
    n = read_int(fp);
    printf("n = %dn", n);
    write_int(fp, n + 10);
    fclose(fp); /* 1 11 3 */

    /* read */
    fp = xfopen(filename, "r");
    for(i = 0; i < 3; i++)
        printf("%dn", read_int(fp));
    fclose(fp);

    return 0;

}

Je commence par écrire 3 entiers dans un fichier.
J'ouvre une deuxième fois le fichier en mode rb+, je lis le premier
entier, et j'écris à la suite.

Problème, sous Ubuntu, cette écriture fonctionne bien, et l'affichage
du contenu du fichier me donne bien 1, 11, 3, qui est le résultat
attendu.
Sous Windows par contre, le fichier contient toujours 1, 2, 3.

J'ai fait quelques tests avec ftell entre la lecture et l'écriture, et
la valeur retournée est normale(la taille d'un entier).

Une explication?

Merci d'avance.



Navré, il y a plusieurs coquilles dans le code.
Le même corrigé.
#include #include
FILE *xfopen(char const *path, const char *mode)
{
FILE *fp = fopen(path, mode);
if(fp == NULL)
{
perror("xfopen ");
exit(EXIT_FAILURE);
}
return fp;

}

int read_int(FILE *fp)
{
int ret;
if(fread(&ret, sizeof(int), 1, fp) < 1)
{
fprintf(stderr, "Error: read_int");
exit(EXIT_FAILURE);
}
return ret;

}

void write_int(FILE *fp, int n)
{
if(fwrite(&n, sizeof(int), 1, fp) < 1)
{
fprintf(stderr, "Error : write_int");
exit(EXIT_FAILURE);
}

}

int main(void)
{
int i, n;
char const *filename = "test.txt";
FILE *fp = NULL;

/* write */
fp = xfopen(filename, "wb");
for(i = 0; i < 3; i++)
write_int(fp, i + 1);
fclose(fp); /* 1 2 3 */

/* read / write */
fp = xfopen(filename, "rb+");
n = read_int(fp);
printf("n = %dn", n);
write_int(fp, n + 10);
fclose(fp); /* 1 11 3 */

/* read */
fp = xfopen(filename, "rb");
for(i = 0; i < 3; i++)
printf("%dn", read_int(fp));
fclose(fp);

return 0;

}
Lucas Levrel
Le #22860331
Le 29 novembre 2010, GurneyH a écrit :

Sous Windows par contre, le fichier contient toujours 1, 2, 3.



Les droits d'accès sur test.txt sont-ils bons ?

--
LL
GurneyH
Le #22860471
On 29 nov, 11:26, Lucas Levrel
Le 29 novembre 2010, GurneyH a écrit :

> Sous Windows par contre, le fichier contient toujours 1, 2, 3.

Les droits d'accès sur test.txt sont-ils bons ?

--
LL



Je ne pense pas.
Le fichier est créé par le programme. (premier fopen avec "w").
De plus, si c'était un problème de droits d'accès, fopen retournerait
un pointeur NULL, et perror m'indiquerait ce problème, non?
Antoine Leca
Le #22861521
GurneyH écrivit :
Je suis peu habitué à manipuler des fichiers en lecture/écriture, et
je me trouve avec un code qui produit un résultat différent suivant
qu'il est compilé et exécuté sous Ubuntu et GCC ou Windows et MingW.





Ta première version écrivait en texte et relisait en binaire, clairement
c'est un mélange des genres... mais c'est corrigé.

Cela étant, les fichiers binaires ou textes n'ont rien à voir dans ton
problème : tu obtiens exactement le même résultat avec des fichiers texte.


Je commence par écrire 3 entiers dans un fichier.

J'ouvre une deuxième fois le fichier en mode rb+, je lis le premier
entier, et j'écris à la suite.

Problème, sous Ubuntu, cette écriture fonctionne bien, et l'affichage
du contenu du fichier me donne bien 1, 11, 3, qui est le résultat
attendu.
Sous Windows par contre, le fichier contient toujours 1, 2, 3.





Oui, j'obtiens la même chose, y compris avec SUA (le POSIX de Windows).
Ce qui me semble une non-conformité de la part de Microsoft.


Une explication?





À vue de nez, l'implémentation de stdio de Microsoft ne respecte pas la
norme pour un fichier ouvert en "r+" ou "rb+" : si tu fais une lecture
suivie directement d'une écriture (sans remise-à-zéro de l'état du
tampon), l'écriture n'est pas prise en compte au moment de fermer le
fichier, l'implémentation fait comme si le fichier était encore en mode
lecture et ne met pas à jour le disque :-(

C'est ÀMHA non conforme : la norme précise bien que si tu fais le
contraire (écriture suivi de lecture), un programme pour être conforme
doit faire une remise-à-zéro intermédiaire : en creux, cela veut dire
que dans le sens que tu utilises, cela doit fonctionner.


En même temps, la solution est « simple » : il suffit de rajouter une
opération de remise-à-zéro même si c'est officiellement inutile: essaye
n = read_int(fp);
printf("n = %dn", n);
fseek(fp, 0L, SEEK_CUR); /* remise à zéro du tampon */
write_int(fp, n + 10);


Antoine
GurneyH
Le #22862351
On 29 nov, 15:00, Antoine Leca
GurneyH écrivit :

>> Je suis peu habitué à manipuler des fichiers en lecture/écriture , et
>> je me trouve avec un code qui produit un résultat différent suivan t
>> qu'il est compilé et exécuté sous Ubuntu et GCC ou Windows et Mi ngW.

Ta première version écrivait en texte et relisait en binaire, clairem ent
c'est un mélange des genres... mais c'est corrigé.

Cela étant, les fichiers binaires ou textes n'ont rien à voir dans to n
problème : tu obtiens exactement le même résultat avec des fichiers texte.

>> Je commence par écrire 3 entiers dans un fichier.

>> J'ouvre une deuxième fois le fichier en mode rb+, je lis le premier
>> entier, et j'écris à la suite.

>> Problème, sous Ubuntu, cette écriture fonctionne bien, et l'affich age
>> du contenu du fichier me donne bien 1, 11, 3, qui est le résultat
>> attendu.
>> Sous Windows par contre, le fichier contient toujours 1, 2, 3.

Oui, j'obtiens la même chose, y compris avec SUA (le POSIX de Windows).
Ce qui me semble une non-conformité de la part de Microsoft.

>> Une explication?

À vue de nez, l'implémentation de stdio de Microsoft ne respecte pas la
norme pour un fichier ouvert en "r+" ou "rb+" : si tu fais une lecture
suivie directement d'une écriture (sans remise-à-zéro de l'état d u
tampon), l'écriture n'est pas prise en compte au moment de fermer le
fichier, l'implémentation fait comme si le fichier était encore en mo de
lecture et ne met pas à jour le disque :-(

C'est ÀMHA non conforme : la norme précise bien que si tu fais le
contraire (écriture suivi de lecture), un programme pour être conform e
doit faire une remise-à-zéro intermédiaire : en creux, cela veut di re
que dans le sens que tu utilises, cela doit fonctionner.

En même temps, la solution est « simple » : il suffit de rajouter u ne
opération de remise-à-zéro même si c'est officiellement inutile: essaye
    n = read_int(fp);
    printf("n = %dn", n);
    fseek(fp, 0L, SEEK_CUR);    /* remise à zéro du tampon */
    write_int(fp, n + 10);

Antoine



En effet, le code fonctionne en plaçant
fseek(fp, 0L, SEEK_CUR); /* remise à zéro du tampon */
entre les 2 opérations. :)

Merci beaucoup pour la solution, ainsi que pour l'explication .

GurneyH
Publicité
Suivre les réponses
Poster une réponse
Anonyme