Ecriture de fichiers à partir d'un programme C

Salut!

Voilà, j’ai écrit un programme en C, capable de fonctionner sous Windows et sous Linux, mais lorsque ce programme veut enregistrer des paramètres dans un fichier, sous Linux j’ai des problèmes.

Mon programme utilise les fonctions fopen, fwrite, et fclose, normalement.
Je souhaite ouvrir le fichier et ajouter des choses à la fin, sous Windows, normal, je fais comme ça (pour enregistrer un tableau contenant 30 caractères):

fic = fopen( "fichier.sav" , "a+b" ); fwrite( &tableau_chaine_caractères[0] , sizeof(type) , 30 , fic ); fclose( fic );

Sous Windows, ça marche très bien, a chaque lancement du programme j’ai la chaine en question qui s’écrit à la fin du fichier.

Sous Linux, au premier lancement ça fonctionne, il m’enregistre la chaine, mais si je relance mon programme à nouveau, il n’écrit rien dans le fichier (il laisse la chaine de caractères écrite la première fois, sans rien ajouter dans le fichier).

J’ai essayé de remplacer a+ par a, même par w, rien n’y fait, le fichier contiendra toujours uniquement la première chaine enregistrée par le programme.

De même, si j’utilise fwrite à nouveau avant d’avoir fait fclose, il m’enregistre que le contenu de la variable du premier fwrite.

Bref, il doit y avoir une subtilité, une différence pour enregistrer des fichiers en C sous Linux non ?

J’ai vérifié les droits du fichier dans lequel je veux écrire, ils sont OK.

Voilà, si vous pouviez m’aider… !

la premiere et indispensable etape est d arreter de faire le cochon:
toujours verifier les valeurs de retour. non, sans dec. toujours. la tu manipule des fichiers, c est pas bien grave si ca foire, si tu code une appli qui joue avec kmem et les devices c est une autre histoire.

deja tu saura si de son point de vue ca c est bien passe.

apres si tu ne trouve pas la valeur supposee:

[quote]      fread  does  not distinguish between end-of-file and error, and callers
      must use feof(3) and ferror(3) to determine which occurred.[/quote]
(sinon read et write marchent tres bien :P)

[code]fic = fopen( “fichier” , “a+b” );

printf( “%d " , fwrite( &chaine[0] , sizeof(char) , 30 , fic ) );
printf(”%d ", fwrite ( &nombre , sizeof(int) , 1 , fic ) );

printf( “%d %d” , ferror(fic) , feof(fic) );

fclose(fic);[/code]Me renvoie: “30 1 … 0 0”.
Je sais pas si j’utilise correctement ferror et feof… en tout cas tous les fwrite me donnent le bon nombre de blocs écrits, alors que seulement le premier écrit quelque chose.

Tu ne peux pas mettre tout le code ? à mon avis tu as un bug dans ton appli :P"

Je veux bien mettre tout le code, mais c’est un programme de TP vrément basique, je pense pas que ce soit utile (d’autant plus que le programme marche très bien sous Windows).

Enfin bon, voici tout le code, qui n’est pas encore terminé:

[code]// TP 10.1

#include <stdio.h>

// définition de la structure
typedef struct
{
char nom[30];
int age;
float notes[3];
} etudiantii;

void saisie(etudiantii *etudiant);
float moyenne(etudiantii *etudiant,int nb_notes);
void affiche(etudiantii *etudiant,float moyenne);

int main()
{
float moy=0.0;
char continuer;
int i;
FILE *fic;
etudiantii eleve;     // déclaration d’une variable avec le type défini par la structure

fic = fopen("etudiants_ii.txt","a+b"); &nbsp; &nbsp; // ouverture du fichier

do
{

 saisie (&eleve);
 
 moy = moyenne(&eleve,3);
 
 affiche (&eleve,moy);

 printf("%d “,fwrite(&eleve.nom[0],sizeof(char),30,fic));
 printf(”%d “,fwrite(&eleve.age,sizeof(int),1,fic));
 
 for (i=0;i<3;i++)
 {
 fwrite(&eleve.notes[i],sizeof(float),1,fic);
 }
 fwrite(&moy,sizeof(float),1,fic);
 
 printf(”%d %d",ferror(fic),feof(fic));
 
 printf("Entrer un autre étudiant? (o/n) ");
 getchar();
 continuer = getchar();
 getchar();
 
} while (continuer != ‘n’);

fclose(fic); &nbsp; &nbsp; // fermeture du fichier

}

void saisie(etudiantii *etudiant)
{
int i,nb;

printf("\nEntrez le nom: ______________________________\r");
printf("Entrez le nom: ");
gets(etudiant->nom);
&nbsp;
printf("Entrez l'age: ");
scanf("%d",&etudiant->age);

printf("Entrez les notes:\n");
for (i=0;i<3;i++)
{

 do
 {
 printf("   note %d: “,(i+1));
 scanf(”%f",&etudiant->notes[i]);
 
 if (etudiant->notes[i] > 20 || etudiant->notes[i] < 0)
 {
   printf(“Entrée incorrecte!\n”);
 }
 
 } while (etudiant->notes[i] > 20 || etudiant->notes[i] < 0);
}
}

float moyenne(etudiantii *etudiant,int nb_notes)
{
int i;
float moy;

moy = 0;

for (i = 0;i < (nb_notes);i++)
{

 moy = moy + etudiant->notes[i];
}

moy = moy / nb_notes;

return moy;

}

void affiche(etudiantii *etudiant,float moyenne)
{
printf("\nLes informations entrées concernent %s, agé de %d ans.\nLes 3 notes entrées sont:\n   %.1f\n   %.1f\n   %.1f\nSa moyenne est de %.1f\n\n",etudiant->nom, etudiant->age,etudiant->notes[0],etudiant->notes[1],etudiant->notes[2],moyenne);
}[/code]

En faites sauf si je suis complement stupide ca fait quoi fopen avec l option a+b ?

Parce que le man fopen il dit :

[quote]DESCRIPTION
      The fopen function opens the file whose name is the string pointed to by path and associates a stream with it.
                                                                                                                           
      The  argument  mode  points  to a string beginning with one of the following sequences (Additional characters may
      follow these sequences.):
                                                                                                                           
      r      Open text file for reading.  The stream is positioned at the beginning of the file.
                                                                                                                           
      r+    Open for reading and writing.  The stream is positioned at the beginning of the file.
                                                                                                                           
      w      Truncate file to zero length or create text file for writing.  The stream is positioned at  the  beginning
              of the file.
                                                                                                                           
      w+    Open  for  reading and writing.  The file is created if it does not exist, otherwise it is truncated.  The
              stream is positioned at the beginning of the file.
                                                                                                                           
      a      Open for appending (writing at end of file).  The file is created if it does not  exist.  The  stream  is
              positioned at the end of the file.
                                                                                                                           
      a+    Open  for  reading and appending (writing at end of file).  The file is created if it does not exist.  The
              stream is positioned at the end of the file.[/quote]

Ca pauserai pas un probleme ca ?

Koubiak que peut etre …

Bah chez moi ça fonctionne… j’ai fait un copié-collé et pas de prob, il ajoute bien de nouveaux etudiants, même après avoir relancé le prog…

par contre gcc a pas l’air d’aimer gets… : warning: the `gets’ function is dangerous and should not be used. faudrait utiliser fgets, car gets ne regarde pas la taille de ton buffer -> segmentation fault si l’utilisateur entre trop de caractères…

J’ai lu l’ensemble du code et je n’y ai pas trouvé de prob.

Peux-tu juste ajouter un path à l’ouverture du fichier, stp. genre “./mon_fichier.txt” pour voir ou bien même un path en absolu.

Ah!
Je crois avoir trouvé la cause du problème…

Je ne sais pas pourquoi, mais kwrite semble m’afficher que le premier truc que j’ai sauvé dans le fichier, peut être que lorsque il rencontre les caractères spéciaux (les notes et tout le reste) il s’arrête d’afficher car les polices utilisées ne gèrent pas du tout ces caractères…
J’avais pensé à ça, mais vu que la taille du fichier ne changeait pas dans konqueror je pensai qu’il n’ajoutai rien… et je pensai de plus avoir déjà vérifié le contenu avec nano, et à l’instant je me souvient que ce n’était pas le cas.

J’ai essayé d’éditer avec nano, et il m’affiche quelques caractères spéciaux.

Peut être donc que ça fonctionne. Sûrement même! Je vous tiens au courant quand j’aurais ajouté la partie qui charge le fichier dans le programme voir si tout est restitué normalement, mais a mon avis ce devrait être bon!

Comme quoi des fois un simple bug à la con! Ca me dégoutai un peu de buter sur un programme aussi simple :stuck_out_tongue:

J’ai pas le temps de lire le code mais, juste pour info, l’option « b » du fopen n’existe que sous windows, c’est pour forcer fopen a ecrire en binaire au lieu du mode texte, car sous win/dos, \n est remplace par \r\n quand on est en mode texte.
« b » n’a pas de sens sous Unix, meme si fopen unix ne considere pas ca comme une erreur (ca change rien de le mettre ou non), juste que le soft est compatible avec windows.

LoneWolf
MS fait rien comme tout le monde :stuck_out_tongue:

[quote]The character b has no effect, but is allowed for ISO C
standard conformance[/quote]

C’est du code ISO non revu ANSI, c’tout.

"MS fait rien comme tout le monde " :stuck_out_tongue:

C’est qui tout le monde ? Personnellement je trouve beaucoup plus rusé de séparer le retour en début de ligne et le saut de ligne que de coupler forcément les deux. M’enfin c’est un autre sujet.

bluelambda> je ne comprends rien à ce que tu fais. Tu essaies de regarder le contenu d’un fichier binaire avec un éditeur de texte ? :stuck_out_tongue:

Dump le contenu avec od par exemple pour en avoir une image (en octal par défaut… muhuhahaha… – cf. man od --)

Est ce que quelqu’un sait comment faire pour supprimer une entrée dans le fichier?

Mettons que j’ai écrit dans mon fichier les valeurs de a, puis b, puis c.
Une fois suivante, je relance mon programme et je souhaite supprimer b (écrit dans le fichier entre a et c), comment puis-je procéder?

Méthode bête et méchante :
tu charge le fichier en mémoire, tu vire ce dont tu n’as plus besoin, et tu reballances tout dans le fichier. Evidemment il va falloir écrire une fonction Load et une Save ainsi que de quoi traiter le tout en mémoire.

Méthode plus compliqué :
si tu connais l’ID (enfin la position de la strucutre dans le fichier) de l’étudiant tu peux arriver à determiner l’offset de ta valeur à modifier, et faisant mumuse avec fsetpos tu peux arriver là où tu veux. Pour supprimer suffit de faire des aller/retour en lisant/écrivant.

Perso je ferais plutôt la première méthode, sachant que la taille des fichiers est plutôt réduite :stuck_out_tongue:

OK merci de ton aide!

Au faite, chuis con de pas y avoir pensé avant, mais au lieu d’enregistrer un par un les champs de la structure, j’aurais pu enregistrer tout simplement la structure (1 bloc, sizeof type de la structure). Ca marche :stuck_out_tongue:

En effet, c’est le principe du serialize :stuck_out_tongue: