Ecriture/Lecture de fichier binaire (ios::binary) avec << et >>

Ecriture/Lecture de fichier binaire (ios::binary) avec << et >> - C++ - Programmation

Marsh Posté le 21-09-2004 à 11:08:50    

Bonjour,
 
Un petit souci ...
 
Je souhaiterais écrire un fichier en binaire en C++. J'ouvre mon fichier "Data.d" et j'écris un entier par :
 
char* ident = "Data.d";
ofstream ofs;
int numb = 1234;
 
ofs.open(ident,ios::out|ios::binary);
 
ofs.write((int *) &numb,sizeof(int));
 
Apparemment, la valeur est correctement enregistrée car une opération de lecture en binaire par la commande ifs.read(...) (le fichier "Data.d" est rouvert et lu par un ifstream) réussit. Cependant, j'avais souhaité faire plus simple avec la commande :
 
ofs << numb;
 
en remplacement de la ligne  
 
ofs.write((int *) &numb,sizeof(int));
 
Or, cette opération me donne la forte impression de correspondre à une écriture en ASCII (notamment car la commande more permet la relecture du fichier qui contient la valeur), alors même que le fichier "Data.d" doit être écrit en binaire, ce qui est expliciement spécifié dans la ligne :
 
ofs.open(ident,ios::out|ios::binary);
 
D'où vient le problème. Pourquoi une écriture par la commande << ne permet t'elle pas une écriture du fichier en binaire ? Est-il possible de se passer de la commande (loure à mon avis) " ofs.write((int *) &numb,sizeof(int)); " pour forcer l'écriture en binaire ?
 
 
 

Reply

Marsh Posté le 21-09-2004 à 11:08:50   

Reply

Marsh Posté le 21-09-2004 à 11:17:50    

Bon ...
 
Il semble qu'il y ait eu une mauvaise lecture de certains caractères. Les petites têtes ont replacés ce que j'avais tapé. Il fallait lire la constante d'ouverture en écriture d'un fichier, accompagné du mode d'ouverture binaire :
 
ios :: out|ios :: binary
 
J'ai mis un espace entre les :: et les ios, out et binary pour que ça puisse passer (en espérant que ça marche !).
 
E

Reply

Marsh Posté le 21-09-2004 à 11:32:59    

c'est quoi ces cast à la con ?
pourquoi t'utilise pas le constructeur ?

Reply

Marsh Posté le 21-09-2004 à 11:47:19    

>> c'est quoi ces cast à la con ?  
>> pourquoi t'utilise pas le constructeur ?
 
Comme j'ai déja du le dire, je suis débutant en C++ (surtout par rapport aux membres les plus actifs de ce forum). De toutes façons, il y a, en fait, bcp plus de choses à lire que ça, donc un constructeur seul est peutêtre trop simple.
 
En fait ce qui me pose problème, c'est déja ce choix de commande pour écrire un fichier binaire !  
 

Reply

Marsh Posté le 21-09-2004 à 12:01:59    

ben si tu fais
 
 
ifstream f;
 
 
et 100 lignes plus bas que tu appelles open, y a un problème
 
 
 
quand au reste, c'est pourtant simple : y a deux sémantiques différentes, donc deux façons de coder. D'un côté les << et >> surchargés, de l'autre les fonctions membres .read et .write

Reply

Marsh Posté le 21-09-2004 à 13:10:26    

Excuse moi, mais je ne te comprends pas. Je cherche juste à écrire plusieurs valeurs dans un fichier, c'est tout !
 
Quand à ma question, c'est juste de savoir si les commandes  :
 
ofs.write((int *) &numb,sizeof(int));  
 
et :
 
ofs << numb;  
 
sont équivalentes quand il s'agit d'écrire des valeurs dans un fichier binaire. Visiblement, pour moi ce n'est pas le cas. La première fait ce que j'attends mais la seconde me donne l'impression de procéder à une écriture ASCII. D'où viens ce problème ? Est ce que les sémantiques sont équivalentes comme le dit Taz pour des fichiers binaires ou ce n'est plus le cas dans une telle situation ?

Reply

Marsh Posté le 21-09-2004 à 15:59:16    

Juste un autre point :
 
Est ce dangereux d'utiliser les cast tels que je le fais. En effet, si je veux mettre un entier ou un double en binaire dans un fichier et que << ne semble pas marcher, je suis obligé de me rabattre vers la commande write. Or celle-ci, selon sa déclaration, ne devrait accepter que les pointeur du type char* en premier argument. En en utilisant un autre (ie. (int *) ), cette écriture semble pourtant fonctionner (en regardant ce qui se passe pour la lecture). Est ce dangereux ? Si << surchargé ne fonctionne pas, comment puis-je avec la commande write, faire une écriture en binaire d'un entier ou d'un double ?
 

Reply

Marsh Posté le 21-09-2004 à 18:01:50    

si t'as arrêter de caster dans tous les sens et que tu écrivais les choses bien ... ça serait plus indolore

Reply

Marsh Posté le 21-09-2004 à 18:11:56    

Bon ...
1)
 
Je voudrais juste une réponse claire à ma question sur l'équivalence des deux écritures pour un fichier binaire.
 
2)
 
Qu'est ce que se serait pour toi, Taz, une écriture propre de :
 
ofs.write((int *) &numb,sizeof(int));
 
si l'on souhaite écrire une variable numb, de type int,  dans un fichier (binaire ou ASCII puisque cette commande write est valable pour les deux types de fichiers, enfin, je crois). Je reconnais que mon bouquin de C++ parle d'un modèle d'écriture en : write(const char* tampon, int max).

Reply

Marsh Posté le 21-09-2004 à 20:17:36    

ofs.write((int *) &numb,sizeof(int));  
si numb est un int, pourquoi tu le recast en int ?
puis doit y avoir un const perdu en plus
ofs.write(&numb, sizeof(int));
 
sinon (type*)&var c'est un cast C, en C++ pour obtenir la meme chose on ecrit dynamic_cast<type*>(&var) ou si on peut résoudre le transtypage a la compilation static_cast<type*>(&var)


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 21-09-2004 à 20:17:36   

Reply

Marsh Posté le 21-09-2004 à 20:46:48    

mais &numb EST un int* !

Reply

Marsh Posté le 22-09-2004 à 00:44:45    

bin oui, c'est ce que j'ai écrit :o
ofs.write(&numb, sizeof(int));


---------------
-( BlackGoddess )-
Reply

Marsh Posté le 22-09-2004 à 00:52:17    

moi j'aime bien le sizeof numb

Reply

Marsh Posté le 22-09-2004 à 09:09:49    

Bon ...
 
Aucune idée de la raison pour laquelle les deux écritures possibles ne donne pas le même résultat pour les fichiers binaires ?
 
Sinon, quel est l'écriture correcte de la commande write si l'on souhaite écrire un int dans un fichier. On a alors , effectivement, un int* en paramètre d'entrée et non un char*. Comme résoudre ce problème ?

Reply

Marsh Posté le 22-09-2004 à 09:32:57    

nathan_g a écrit :

Aucune idée de la raison pour laquelle les deux écritures possibles ne donne pas le même résultat pour les fichiers binaires ?


 
Comme tu l'as bien compris, les flux c'est pour du texte (donc la représentation textuelle des entiers, caractères, etc.), et write c'est pour du binaire (donc, leur représentation machine), c'est tout.  
 
La façon C++, ça serait:  

Code :
  1. osf.write(static_cast<const char *>(&i), sizeof int);


 
 
Mais franchement, mon avis (religieux) personnel, c'est qu'un cast C classique ne fait pas de mal dans le contexte en cours (qui est de détyper un pointeur sur un type primitif pour le passer à une API). Si c'était une affectation de pointeurs sur des types non-basiques (struct ou class), ça serait effectivement à éviter. Les avis diffèrent, et franchement, ça devrait être le cadet de tes soucis...
 

Reply

Marsh Posté le 22-09-2004 à 09:50:56    

OK, merci de cette réponse claire.
Sinon, tu écris que les flux c'est pour du texte ce qui pourrais expliquer mon problème de ne pas pouvoir écrire de fichiers binaires avec ces flux. La, je suis étonné car dans mon bouquin de C++, les écriture de int dans des fichiers ASCII se font par des flux (ex : ofs << i; où i est une variable int). Leurs lectures se fait également par des flux (ex : ifs >> i;) et ça fonctionne.
Il est donc possible d'écrire des variables int dans des fichiers ASCII et de les relire. Ou alors, je n'ai pas très bien compris ce que tu entends par "texte". Tu voulais peut-être me dire qu'il s'agissait de fichiers ASCII et que les flux sont des méthodes d'écriture/lecture réservées aux fichiers ASCII ?
 
Sur le second point, je vais peut être adoptée quand même, par propreté l'écriture :
 
osf.write(static_cast<const char *>(&i), sizeof int);
 
Mais d'après ce que j'ai cru comprendre, il n'y aucun risque dans l'éxécution à écrire :
 
ofs.write((int *) &numb,sizeof(int));  
 
A part que mon compilateur affiche alors un warning pour cette ligne.

Reply

Marsh Posté le 22-09-2004 à 09:51:43    

( ifs >> i ; ) bien sur.

Reply

Marsh Posté le 24-09-2004 à 17:58:03    

UP !
 
Je reviens sur mon post car j'aimerais avoir confirmation des questions que je continue à me poser.
 
De plus, j'ai toujours ce problème d'écrire dans des fichiers. La commande :
 
ofs << value;
 
m'écrit des variables de manière claire dans des fichiers, donc crée un fichier de type ASCII.
 
La commande  
 
ofs.write((int* ) &value,sizeof(int));
 
m'écrit des variables apparemment en binaire (car les fichiers sont illisibles avec more).
 
En plus, le fonctionnement de ces commandes semble indépendant du format d'ouverture du fichier (ie. que l'instruction ios::binary soit ou non préciser à l'ouverture du fichier dans la commande ofs.open("Mon fichier",ios::out|ios::binary).
 
D'où vient ce comportement ?

Reply

Marsh Posté le 25-09-2004 à 18:56:02    

Ben c'est fait comme ça, c'est le comportement voulu. L'opérateur << manipule des flux text, pas binaire. Faire un truc genre :
fichier << ios_base::binary << 11;
devrait plutot afficher "1011" (11 en binaire, mais toujours sous forme texte). C'est la seule manière d'avoir une sortie portable, i.e. pas avoir de problemes de little/big endian.
Pour écrire en binaire on utilise write. Ca écrit des octets. Un cast bête est pratique mais sans garantie de portabilite. L'ideal est de choisir une représentation binaire et d'avoir des routines qui en fonction du système transforme (ou non) les données en mémoire dans ce format binaire décidé. Idem pour la lecture.
Je sais qu'il y a boost::serialization pour ça, mais j'ai pas testé.
Pour une utilisation "interne" restreinte, un truc du genre fait l'affaire :

Code :
  1. template<typename T>
  2. void write( std::ofstream & Stream, T Value )
  3. {
  4.     Stream.write( reinterpret_cast<char*>( &Value ), sizeof T );
  5. }


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 25-09-2004 à 19:02:54    

mais pourquoi typer en ofstream bordel :o
 
et une chtite référence siouplé pour Value

Reply

Marsh Posté le 27-09-2004 à 01:33:51    

Taz a écrit :

mais pourquoi typer en ofstream bordel :o


Pas compris.


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 27-09-2004 à 20:18:57    

pourquoi avoir fait une fonction pour ofstream uniquement ?

Reply

Marsh Posté le 28-09-2004 à 08:57:11    

Bon, je vais essayer la proposition de HelloWorld.
Mais, je reste sur ma fin. Je n'ai toujours pas compris l'intérêt d'écrire ios::binary au début du programme vu que le format d'écriture (respectivement lecture) est guidé uniquement par le choix de << (respectivement >> ) ou de write (respectivement read). Dans le premier, c'est de l'ASCII, dans le second du binaire. Etonnant non ?

Reply

Marsh Posté le 28-09-2004 à 09:17:56    

Oui. ios_base::binary influe sur les retours chariots. Sous Windows y'a 2 carcatères pour revenir à la ligne, sans binary c'est comme si y'en avait qu'un.


---------------
FAQ fclc++ - FAQ C++ - C++ FAQ Lite
Reply

Marsh Posté le 28-09-2004 à 09:19:52    

D'expérience, lire ou écrire avec ostream::write et istream::read sans préciser que le flux est de type binaire entraine des erreurs (ton fichier comporterait des anomamlies!).


---------------
Cordialement, Xterm-in'Hate...
Reply

Marsh Posté le 28-09-2004 à 09:37:58    

OK, Merci beaucoup !
 
Enfin, la réponse que j'attendais. Je vais revoir mon programme en reconsidérant tout ça et en utilisant le petit programme de HelloWorld.
 
Pour information, ce que je dois faire est en fait la relecture, par mon programme C++, d'un fichier binaire écrit en fortran 77. On découvre des caractères surprise !
 
Par tatonnement, j'ai d'ailleurs découvert que l'écriture d'un ensemble de valeurs, en fortran, se faisait en rajoutant des données supplémentaires indiquant la taille des variables.
 

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

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