OVH Cloud OVH Cloud

Lecture / écriture dans un fichier binaire

16 réponses
Avatar
GurneyH
Bonjour.

Je suis peu habitu=E9 =E0 manipuler des fichiers en lecture/=E9criture, et
je me trouve avec un code qui produit un r=E9sultat diff=E9rent suivant
qu'il est compil=E9 et ex=E9cut=E9 sous Ubuntu et GCC ou Windows et MingW.

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

FILE *xfopen(char const *path, const char *mode)
{
FILE *fp =3D fopen(path, mode);
if(fp =3D=3D 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 =3D "test.txt";
FILE *fp =3D NULL;

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

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

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

return 0;
}

Je commence par =E9crire 3 entiers dans un fichier.
J'ouvre une deuxi=E8me fois le fichier en mode rb+, je lis le premier
entier, et j'=E9cris =E0 la suite.

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

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

Une explication?

Merci d'avance.

6 réponses

1 2
Avatar
Tonton Th
On 12/01/2010 12:02 PM, -ed- wrote:

A votre connaissance, l'utilisation du mode "+" est fréquente, ou
reste anecdotique?



Personnellement, j'évite, car c'est une magnifique machine à broyer
les fichiers ...



J'aimerais bien que tu nous montres un petit et horrible exemple.

--
Ma coiffeuse est formidable - http://sonia.buvette.org/
Avatar
GurneyH
On 1 déc, 13:01, Antoine Leca wrote:
GurneyH crivit :

> Norme C99 7.19.5.3

> "When a file is opened with update mode ('+' as the second or
> third character in the above list of mode argument values),
> both input and output may be performed on the associated
> stream. However, output shall not be directly followed by input
> without an intervening call to the fflush function or to a file
> positioning function (fseek, fsetpos, or rewind),

Jusque l j'avais lu...

> and input shall not be directly followed by output without an
> intervening call to a file positioning function, unless the input
> operation encounters end-of-file. [...]"

Mais j'avais saut cette important phrase ! :+|  D sol .

Effectivement, il semble donc bien que la solution de Microsoft est
conforme. Pan sur le bec.

> De la norme, je comprend:
> Avec un fichier ouvert en mode "+"
> lecture -> (rewind, fpos, fseek) -> criture
> citure -> fflush -> lecture

  lecture -> re u EOF _ou_ rewind/fseek/fsetpos -> criture

  criture -> fflush/rewind/fseek/fsetpos -> lecture

> A votre connaissance, l'utilisation du mode "+" est fr quente,
> ou reste anecdotique?

Je ne dirait pas que c'est fr quent, mais "r+" n'est pas anecdotique,
c'est le mode normal pour ouvrir un fichier que tu sais exister et que
tu veux modifier (et oui, ce n'est pas vident; le mode quivalent en
POSIX est O_RDWR, c'est quand m me plus clair.)

"w+" et "a+" me paraissent eux anecdotiques, mon sens ils sont plus l
pour la sym trie (de l'impl mentation originale de stdio en 1976) que
pour autre chose.

Antoine



J'ai l'impression, (il me semble que c'est le point de vue de -ed-
(bonjour -ed-.)), que souvent:
- on ouvre un fichier en lecture seule
- on copie l'intégralité en mémoire,
- on effectue les traitements
- on crée un autre fichier que l'on renomme

d'autres schémas existent?
Avatar
espie
In article ,
GurneyH wrote:

J'ai l'impression, (il me semble que c'est le point de vue de -ed-
(bonjour -ed-.)), que souvent:
- on ouvre un fichier en lecture seule
- on copie l'intégralité en mémoire,
- on effectue les traitements
- on crée un autre fichier que l'on renomme

d'autres schémas existent?



Oui. On peut tres bien vouloir rajouter des choses en fin de fichier apres
avoir lu certaines infos. Il faut juste faire attention aux histoires de
synchro et utiliser correctement fseek ou rewind quand on passe de lecture a
ecriture.
Avatar
-ed-
On 1 déc, 13:55, GurneyH wrote:
On 1 déc, 13:01, Antoine Leca wrote:



> GurneyH crivit :

> > Norme C99 7.19.5.3

> > "When a file is opened with update mode ('+' as the second or
> > third character in the above list of mode argument values),
> > both input and output may be performed on the associated
> > stream. However, output shall not be directly followed by input
> > without an intervening call to the fflush function or to a file
> > positioning function (fseek, fsetpos, or rewind),

> Jusque l j'avais lu...

> > and input shall not be directly followed by output without an
> > intervening call to a file positioning function, unless the input
> > operation encounters end-of-file. [...]"

> Mais j'avais saut cette important phrase ! :+|  D sol .

> Effectivement, il semble donc bien que la solution de Microsoft est
> conforme. Pan sur le bec.

> > De la norme, je comprend:
> > Avec un fichier ouvert en mode "+"
> > lecture -> (rewind, fpos, fseek) -> criture
> > citure -> fflush -> lecture

>   lecture -> re u EOF _ou_ rewind/fseek/fsetpos -> criture

>   criture -> fflush/rewind/fseek/fsetpos -> lecture

> > A votre connaissance, l'utilisation du mode "+" est fr quente,
> > ou reste anecdotique?

> Je ne dirait pas que c'est fr quent, mais "r+" n'est pas anecdotique,
> c'est le mode normal pour ouvrir un fichier que tu sais exister et que
> tu veux modifier (et oui, ce n'est pas vident; le mode quivalent en
> POSIX est O_RDWR, c'est quand m me plus clair.)

> "w+" et "a+" me paraissent eux anecdotiques, mon sens ils sont plus l
> pour la sym trie (de l'impl mentation originale de stdio en 1976) que
> pour autre chose.

> Antoine

J'ai l'impression, (il me semble que c'est le point de vue de -ed-
(bonjour -ed-.)), que souvent:
- on ouvre un fichier en lecture seule
- on copie l'intégralité en mémoire,
- on effectue les traitements
- on crée un autre fichier que l'on renomme

d'autres schémas existent?



Le traitement à la volée.On lit le fichier A enregistrement par
enregistrement, et on le copie au fur et à mesure dans un ficher B.
Avant de copier,on teste l'enregistrement courant et on fait un
traitement si nécessaire (suppression, insertion, modification etc.).
On se retrouve en fin de traitement avec A (l'ancien, donc annulation
encore possible) et B, le nouveau. Quand on confirme l'opération,on
peut alors supprimer (ou renommer A) et renommer B en A. C'est
certainement assez long avec de gros fichiers, mais pour ça, on
utilisera plutôt une vraie base de données comme TinySQL, par exemple
(pratique en embarqué ...) ou plus (PostgreSQL etc.).L'avantage de ce
principe est qu'il fonctionne quelle que soit la taille du fichier et
ne consomme que très peu de mémoire.
Avatar
Antoine Leca
GurneyH écrivit :
J'ai l'impression, (il me semble que c'est le point de vue de -ed-
(bonjour -ed-.)), que souvent:
- on ouvre un fichier en lecture seule
- on copie l'intégralité en mémoire,
- on effectue les traitements
- on crée un autre fichier que l'on renomme



Quel est l'intérêt du 2e point (copier l'intégralité en mémoire) du
point de vue de la gestion de fichiers ?

Évidemment, cela peut être requis par la structure des données (par
exemple, si tu veux manipuler l'ensemble des données de manière globale,
par exemple pour faire une recherche de doublons par équivalence, comme
quand on ne tient pas compte de la casse).
Mais du point de vue de la gestion de fichiers, ce n'est pas strictement
nécessaire, et de plus la plupart des algorithmes fonctionnent de
manière incrémentale, héritage du temps pas si lointain où l'ensemble
des données ne tenait pas en mémoire centrale...

Si tu ne fais pas la lecture intégrale, tu retombes assez vite sur le
traitement « à la volée » décrit pas Emmanuel, qui est aussi le modèle
traditionnel de traitement des données dans les programmes par lots
(et aussi le mode de fonctionnement interne de beaucoup d'algorithme de
bases de données ; eux ajoutent souvent les données nouvelles au bout du
fichier comme expliqué par Marc, plutôt que dans un fichier séparé).


d'autres schémas existent?



Tu peux utiliser un index ; cet index, outre qu'il te permet d'avoir des
ordres de tri différents ou multiples, peut aussi garder l'information
des emplacements vides ; avec stdio, cela revient à utiliser fsetpos ou
fseek avant chaque écriture ; on peut aussi adapter la taille du tampon
avec setvbuf. Un inconvénient est que tu passes d'une méthode d'accès
séquentiel à un accès aléatoire, ce qui peut avoir un impact sensible
sur les performances (la plupart des systèmes sont optimisés pour
l'accès séquentiel).

Cet index sera souvent dans un fichier différent et plus petit, mais il
peut aussi être constitué en mémoire préalablement au traitement réel :
une première passe de lecture à travers tout le gros fichier pour
repérer les endroits intéressants, que l'on enregistre au passage avec
des fgetpos ou des ftell. C'est par exemple un modèle de traitement
employé pour des programmes de traitements de texte, qui disposent de
temps libre pour effectuer des opérations en arrière-plan et ne traitent
à un instant donné qu'une petite partie du fichier.


Antoine
Avatar
GurneyH
On 2 déc, 11:47, Antoine Leca wrote:
GurneyH crivit :

> J'ai l'impression, (il me semble que c'est le point de vue de -ed-
> (bonjour -ed-.)), que souvent:
> - on ouvre un fichier en lecture seule
> - on copie l'int gralit en m moire,
> - on effectue les traitements
> - on cr e un autre fichier que l'on renomme

Quel est l'int r t du 2e point (copier l'int gralit en m moire) du
point de vue de la gestion de fichiers ?

videmment, cela peut tre requis par la structure des donn es (par
exemple, si tu veux manipuler l'ensemble des donn es de mani re globale,
par exemple pour faire une recherche de doublons par quivalence, comme
quand on ne tient pas compte de la casse).
Mais du point de vue de la gestion de fichiers, ce n'est pas strictement
n cessaire, et de plus la plupart des algorithmes fonctionnent de
mani re incr mentale, h ritage du temps pas si lointain o l'ensemble
des donn es ne tenait pas en m moire centrale...

Si tu ne fais pas la lecture int grale, tu retombes assez vite sur le
traitement la vol e d crit pas Emmanuel, qui est aussi le mod le
traditionnel de traitement des donn es dans les programmes par lots
(et aussi le mode de fonctionnement interne de beaucoup d'algorithme de
bases de donn es ; eux ajoutent souvent les donn es nouvelles au bout du
fichier comme expliqu par Marc, plut t que dans un fichier s par ).

> d'autres sch mas existent?

Tu peux utiliser un index ; cet index, outre qu'il te permet d'avoir des
ordres de tri diff rents ou multiples, peut aussi garder l'information
des emplacements vides ; avec stdio, cela revient utiliser fsetpos ou
fseek avant chaque criture ; on peut aussi adapter la taille du tampon
avec setvbuf. Un inconv nient est que tu passes d'une m thode d'acc s
s quentiel un acc s al atoire, ce qui peut avoir un impact sensible
sur les performances (la plupart des syst mes sont optimis s pour
l'acc s s quentiel).

Cet index sera souvent dans un fichier diff rent et plus petit, mais il
peut aussi tre constitu en m moire pr alablement au traitement r el :
une premi re passe de lecture travers tout le gros fichier pour
rep rer les endroits int ressants, que l'on enregistre au passage avec
des fgetpos ou des ftell. C'est par exemple un mod le de traitement
employ pour des programmes de traitements de texte, qui disposent de
temps libre pour effectuer des op rations en arri re-plan et ne traitent
un instant donn qu'une petite partie du fichier.

Antoine



Merci à tous pour vos réponses, et votre patience. :)
J'ai dérivé du problème d'origine, je m'en excuse...
J'ai beaucoup appris, comme à chacune de mes questions posées ici.
Encore merci!

GurneyH
1 2