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.
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.

Poser une question


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;
}
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?
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.
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.
À 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
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