Lecture d'un fichier en mode binaire

Lecture d'un fichier en mode binaire - C++ - Programmation

Marsh Posté le 17-04-2005 à 22:40:38    

Bijour,
 
je suis pas un grand sachem en prog et je ne vois pas trop commment faire pour resoudre le probleme suivant:  
le principe est d'ecrire une suite d'entier en binaire dans un fichier (a chaque entier ajouté, je rajoute un \n je voulais pas me prendre la tete avec une structure plus elaborée).
il faut aussi arriver a lire ces entiers...
mon probleme vient lors de la lecture, en fait quand je lis sequentiellement les données, la derniere ligne du fichier est répétée 2 fois. Je ne sais pas comment eliminer ce probleme.
 
J'ai d'abord pensé à un flush sur cout, mais ca n'a pas eu d'effet, apres je me suis dit que dans ma boucle quand je lis les entiers, il lit 2 fois le dernier entier car le fichier doit se terminer par un \n\0. je suppose qu'il garde dans un tampon le dernier entier lu et qu'il l'affiche une deuxieme fois.
j'ai fait plusieurs tests et je n'arrive vraiment pas a debugger ce probleme, quelqu'un a une solution ?
 
extrait du code (avec qq commentaires) :
 
déclaration de classe:

Code :
  1. class Fichier { //classe fichier
  2. public:
  3. Fichier(char*); //constructeur avec String
  4. Fichier(); //constructeur par defaut
  5. ~Fichier(); //destructeur
  6. void Ecrire(int); //ecrire un int
  7. int saisirEntier(void); //saisir une suite d'entiers
  8. void lire(void); //lire un fichier
  9. void rang(void); //lire un entier dont on connait le rang
  10. private: //membres privés
  11. ofstream ficOut; //descripteur pour ecrire..
  12. ifstream ficIn; //descripteur pour lire..
  13. };


 
implémentation du code fautif:

Code :
  1. void Fichier::lire(void) { //méthode permettant de lire un fichier existant, ouverture en binaire
  2. int entier;
  3. char fichier[20];
  4. cout << "saisir le nom du fichier a ouvrir (max 20 car): ";
  5. cin >> fichier; //saisie du chemin / nom
  6. ficIn.open(fichier, ios::binary); //ouverture du descripteur
  7. if(ficIn.is_open() == 0) {
  8.  cout << "erreur d'ouverture du fichier !\n";
  9.  return;
  10. }
  11. while(!ficIn.eof()) { //tant qu'on est pas a la fin du descripteur
  12.  ficIn >> entier; //on recupere les entiers avec l'opérateur >>  surchargé
  13.  cout << entier << endl; //puis affichage
  14. }
  15. cout.flush(); //flush de cout
  16. ficIn.close(); //fermeture de ficIn
  17. }


 
je vous remercie d'avance ;)

Reply

Marsh Posté le 17-04-2005 à 22:40:38   

Reply

Marsh Posté le 17-04-2005 à 22:47:54    

# int entier;
#     char fichier[20];
#     cout << "saisir le nom du fichier a ouvrir (max 20 car): ";
#     cin >> fichier; //saisie du chemin / nom
 
 
ignoble. vire tes char* et utilise std::string
 
 
#if(ficIn.is_open() == 0)
 
beurk
 
# hile(!ficIn.eof()) { //tant qu'on est pas a la fin du descripteur
#         ficIn >> entier; //on recupere les entiers avec l'opérateur >>  
 
 
perdu ... c'est là ton BUG A CAUSE D'UNE UTILISATION POURRIE DE EOF. HONTE A TOI ET A TOUS LES ENSEIGNANTS QUI PROPAGENT ENCORE ET TOUJOURS CE BUG !
 
while(ficIn >> entier) { ... }
 
 
 
# cout.flush(); //flush de cout
#     ficIn.close(); //fermeture de ficIn
 
inutile

Reply

Marsh Posté le 17-04-2005 à 22:51:58    

merci pour ta réponse diligente.
 
en fait je ne m'y connais pas trop en C++, a la base je connais mieux le C (enfin mieux...).
je vais voir ce que ca donne avec std::string
sinon ca marche ce que tu m'as dit!  
je trouvais ca plutot logique neanmoins le eof, pq j'ai faux ? :x
 
mon prof c'est une moule j'en conviens...
 
dernieres questions car tu as l'air de plutot bien t'y connaitre:
 
j'aimerai acceder directement a un endroit du fichier et le parcourir sequentiellement c'est plutot stupide.
j'ai un souvenir de fseek mais la doc pourrie de vc++ ne m'avance pas tellement. et la j'ai pas nux pour developper correctement :/
exemple: acceder au nième int du fichier ...
 
da last question:
je voudrai ecrire ce pt1 de fichier en binaire, je fais donc ca:
ficOut.open(chemin, ios::out | ios::binary | ios::trunc)
 
ca me prend la tete car je peux le lire directement avec un viewer :/


Message édité par noonio le 17-04-2005 à 22:55:44
Reply

Marsh Posté le 17-04-2005 à 22:57:47    

que ce soit le feof du C ou eof du C++ c'est la même chose. Documente toi. eof qualifie une erreur d'E/S et ne la détecte pas. Je l'ai dit maintes fois sur ce forum (recherche).
 
Pourquoi avec ton utilisation la deuxième ligne se répète 2 fois ? parce que lors de la lecture de la dernière ligne, aucune erreur ne s'est produite. Donc eof() est faux. La prochaine tentative de lecture échoue, il y a erreur. À ce moment là, eof caractérise l'erreur comme fin de fichier.
 
une règle simple : n'utilise JAMAIS eof.
 
 
une écriture complète serait :
 
while(in >> entier) { ... }
 
if(in.eof()) { fin de fichier, ça va }
else { marne, il s'agit vraiment d'une erreur }

Reply

Marsh Posté le 17-04-2005 à 23:01:29    

pour seek : impossible. Un fichier est une simple suite de caractères.
 
si tu dois faire des accès aléatoires, le mieux est sans doute de tout charger dans un std::vector
 

Code :
  1. std::vector<int> entiers;
  2. int entier;
  3. while(in >> entier) { entiers.push_back(entier); }


 
voire

Code :
  1. std::copy(std::istream_iterator<int>(in), std::istream_iterator<int>(), std::back_inserter(entiers));

Reply

Marsh Posté le 17-04-2005 à 23:04:26    

mouais, je vois. je pensais qu'il existait une méthode pour accéder aléatoirement a un fichier, quoi que tu dois pouvoir te la faire toi meme apres quand tu connais la taille de chaque bloc non ?  
enfin bon, non d'apres ce que tu me dis

Reply

Marsh Posté le 17-04-2005 à 23:08:37    

si chaque enregistrement est à taille fixe, typiquement dans un fichier binaire, oui c'est possible. D'ailleurs j'y pense, ton code, c'est pour lire des entiers dans un fichier texte. Si tu ne dois stocker que des entiers, sans portabilité, en mode binaire, tu peux accèder directement  à chaque entier directement.
 
 
Alors tu veux quoi : un fichier texte ou un fichier binaire ?

Reply

Marsh Posté le 17-04-2005 à 23:15:22    

ben un fichier binaire pur juste.

Reply

Marsh Posté le 17-04-2005 à 23:17:23    

et j'ai un doute quant a mon utilisation de open, je fais ca:
 
out.open(nom, ios :: out | ios::binary | ios::trunc)
si je ne mets pas de \n le fichier est parfaitement lisible sous windows directement


Message édité par noonio le 17-04-2005 à 23:18:03
Reply

Marsh Posté le 17-04-2005 à 23:19:10    

1) n'utilise pas open, utilise le constructeur
2) si tu mets des '\n', alors c'est que tu structures ton fichier en ligne, donc c'est du texte.

Reply

Marsh Posté le 17-04-2005 à 23:19:10   

Reply

Marsh Posté le 17-04-2005 à 23:21:12    

argl, je comprends pas tellement ta réponse (oui je suis mauvais :/).
 
la ligne que j'ai mise est dans le constructeur de MA classe.
faudrait ptet que je stock tous mes entiers dans un tableau puis que je les ecrive en bloque apres, du coup je pourrai ecrire en binaire?
 

Reply

Marsh Posté le 17-04-2005 à 23:25:17    

bon, on reprends depuis le début : ton fichier tu veux qu'il soit lisible avec notepad ou pas ?

Reply

Marsh Posté le 17-04-2005 à 23:25:39    

ben non justement je veux un binaire tout moche

Reply

Marsh Posté le 17-04-2005 à 23:29:22    

alors ni '\n' ni >>. Pas la peine de tout stocker dans un tableau (sauf raison d'efficacité)
 

Code :
  1. if(!cin.seekg(index * sizeof integer)) { erreur }
  2. if(!cin.read(reinterpret_cast<char*>(&integer), sizeof integer)) { erreur }
  3. // voilà, tu as lu l'entier à l'<index>


 
ne fais ni trunc, ni rien. juste un ifstream("...", ios::binary) et c'est tout.

Reply

Marsh Posté le 17-04-2005 à 23:34:10    

ah ok... je vais reprendre tout ce que j'ai fait.
 
et du coup pour ecrire je fais idem mais avec write.
 
je te remercie pour m'avoir éclairé ;)
bonne soirée a toi !

Reply

Marsh Posté le 17-04-2005 à 23:40:57    

istream.read / ostream.write
istream.seekg / istream.tellg
ostream.seekp / ostream.tellp

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed