Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

ecriture et lecture de std::string

33 réponses
Avatar
Marc G
je ne sais pas trop quelle méthode choisir pour écrire/lire des chaînes dans
un fichier binaire

1) La première solution :

// pour écrire
// output est un std::fstream&

std::string UneChaine="coucou";
std::size_t len=UneChaine.size();
char const* contents=UneChaine.data();
output.write((char*)&len,sizeof(std::size_t));
output.write((char*)&contents,len);

// pour lire
// input est un std::fstream&

std::size_t len;
input.read((char*)&len,sizeof(std::size_t));
char *contents=new char[len+1];;
input.read((char*)&contents,len);
contents[len]='\0';
UneChaine=std::string(contents);
delete[] contents;

je trouve ça très lourd juste pour récupérer le contenu de la string
(j'ai l'impression de réserver 2 fois inutilement l'espace pour contenir la
chaîne !)

2) la deuxième solution

output << UneChaine

input >> UneChaine

c'est-à-dire que j'écris en mode texte dans mon fichier binaire (a priori,
ça devrait pas poser de problème ?)

Quels sont vos conseils ?
Quels sont les avantages/inconvénients de chaque méthode et est-il possible
d'améliorer la première ?

Merci à vous.
Marc

10 réponses

1 2 3 4
Avatar
Fabien LE LEZ
On Wed, 07 Nov 2007 23:09:49 +0100, Loïc Joly :

Je vois un avantage non cité à un format binaire, c'est qu'il est facile
d'avoir un jeu de donnée où la taille est homogène, ce qui permet de se
déplacer rapidement dans le fichier sans avoir à tout en lire ou à
l'indexer.


Est-ce tellement plus facile à faire en binaire qu'en texte ?

Avatar
Falk Tannhäuser
James Kanze schrieb:
"Marc G" writes:
char const* contents=UneChaine.data();
[...]



output.write((char*)&contents,len);



Tandis qu'ici, la conversion n'est pas nécessaire ; le premier
paramètre de ostream::write est un char const*.


Et le problème est qu'il y a un '&' en trop - le cast convertit un 'char
const**' en 'char*' ce qui n'est certainement pas ce que Marc voulait faire.

Falk



Avatar
James Kanze
On Nov 7, 3:39 pm, Fabien LE LEZ wrote:
On Wed, 7 Nov 2007 10:40:35 +0100, "Marc G" :

euh, là c'est trop compliqué pour moi... :-)))


C'est pourtant plus simple que réfléchir toi-même à des
spécifications, puisqu'elles sont déjà écrites, il n'y a plus
qu'à les implémenter.


Je crois qu'il parlait de l'implémentation, et non la
spécification. En fait, c'est du copier-coller d'une vraie
application, et non du code que j'ai pendu avec une vue
pédégogique. Alors, il y a bien une ou deux choses que je crois
pourraient poser des problèmes -- à commencer par une
utilisation d'une variante à Duff's device à un endroit, mais
c'est possible aussi qu'il ne connaît pas bien les streambuf.

En ce qui concerne l'utilisation de Duff's device, c'est
seulement pour s'assurer que la taille de la chaîne dans le flux
soit un multiple de 4 ; quelque chose qu'exige XDR pour des
raisons historiques, mais dont on pourrait se passer si
l'utilisation est interne.

En ce qui concerne l'utilisation des streambuf, je lui
conseillerais de l'apprendre s'il a à faire des entrées/sorties
binaires. Mais s'il veut, le sputs() correspond plus ou moins au
ostream::write, et le sputc à ostream::put.

Tu comprends maintenant pourquoi je préfère un format texte ?


Ce qui n'est pas forcement plus facile à spécifier:-). (En
revanche, il y a bien d'autres avantages.)

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
James Kanze
On Nov 8, 12:12 am, Falk Tannhäuser
wrote:
James Kanze schrieb:

"Marc G" writes:
char const* contents=UneChaine.data();
[...]



output.write((char*)&contents,len);



Tandis qu'ici, la conversion n'est pas nécessaire ; le premier
paramètre de ostream::write est un char const*.


Et le problème est qu'il y a un '&' en trop - le cast
convertit un 'char const**' en 'char*' ce qui n'est
certainement pas ce que Marc voulait faire.


En effet. Je voyais ce que je croyais ce qu'il voulait faire, et
non ce qu'il a fait.

Mais c'est bien un argument contre la conversion explicite. Sans
la conversion, le compilateur râle, et on remarque l'erreur.
C'est aussi un argument pour les conversions nouveau style :
ici, il faudrait un reinterpret_cast, ce qui doit vraiment tirer
la sonnette d'alarme.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34




Avatar
James Kanze
On Nov 7, 11:00 am, "Marc G" wrote:
Qu'est-ce qui se passe avec ta fonction sur un systèrme 64
bits ? seuls les 32 bits de poids fort sont utilisés pour le
codage des char, c'est ça ?


Peu importe ; c'est la cuisine interne du compilo (ou plutôt du
processeur).
J'ai un entier ; j'effectue 4 fois la division euclidienne par 256, et
j'enregistre les 4 restes successifs. C'est des maths ; ça n'a rien à
voir avec l'agencement de la RAM ou autre considération matérielle.


sauf que les entiers pourraient être codés sur 64 bits, avec
une valeur max supérieure, non ?


Peut-être. La question est plutôt : est-ce que le format défini
du fichier support des chiffres aussi grands ? C'est une des
raisons pourquoi il faut spécifier le format, et puis programmer
ce format, et non n'importe quoi. Que se passe-t-il si l'année
prochaine, on remplace ta machine avec une qui a des entiers de
128 bits ? Tu vas bien vouloir encore lire les données, non ?

En ce qui concerne la longueur d'une chaîne, j'ai du mal à
concevoir un cas où 2^32-1 ne suffit pas. Pour d'autres
utilisations, XDR a aussi quelque chose qu'il appelle un
« hyper-int » ; un entier à 64 bits. Et sinon, il y a
toujours la solution BER, avec des entiers à longueur variable.
(On encode l'entier avec 7 bits par octets, en commençant par le
poids faibles. Le bit fort de chaque octet sauf le dernier est
0, et le bit fort du dernier est 1, ce qui permet à trouver la
fin.)

donc je peux lire dans un sens et pas dans l'autre....


Bien sûr que si. C'est ne pas spécifier qui pose le problème ;
si tu écris 64 bits, et la machine qui lit ne supporte que 32,
par exemple.

Évidemment, il faut que les deux machines (celle qui écrit, et
celle qui lit) ait un type entier assez grand. Il y a toujours
la solution d'écrire une classe BigInteger, pour traiter les
entiers de longueur arbitraire, mais franchement, pour la
longueur d'une chaîne, je ne crois pas que ce soit nécessaire.

Tu as pu voir qu'un format de fichier binaire est un peu
rock'n'roll à gérer. S'il n'y a pas trop de données, je
préfère largement un fichier texte ligne-par-ligne. C'est
lisible (et donc vérifiable et modifiable) directement avec
un éditeur de texte, les spécifications sont généralement
plus faciles à écrire, et le format s'avère souvent plus
souple.


mes fichier comportent surtout des nombres, donc le mode
binaire s'impose.


Pourquoi ? Ici, nos fichiers comportent surtout des nombres
aussi, mais on utilise une représentation texte. Ça marche aussi
bien, et la mise au point et la migration (quand on change de
format du fichier, parce qu'il faut ajouter des informations)
est nettement facilitées.

Le programme écrit des tables de données. Mon premier soucis
est donc que mes clients ne perdent pas leurs données !


C-à-d dire que tu vas vouloir rélire les fichiers après une mise
à jour du matériel. Donc, il faut absolument que tu définisse un
format (texte ou binaire) et que tu écris dans le format défini.

Comme je vois que les fichiers binaires sont très rock'n'roll comme tu dis,
j'ai une idée et
j'aimerais que tu me dises ce que tu en penses : j'écris en début de fichier
la taille des différents types utilisés à l'écriture/lecture...
comme ça ne risque pas de dépasser 255, je peux même l'écrire dir ectement
sur 1 octet.


Alors, là, tu compliques vraiment la vie. Parce que dans les
fonctions de lecture, il faut que tu exploites cette taille.

Pourquoi pas écrire aussi des informations concernantes le
format des données : j'ai bien vu des protocols où il y avait
un drapeau dans l'en-tête du buffer pour dire s'ils étaient
grand-boutien ou petit. (Dans l'encodage BER, on va jusqu'à
spécifier la base des flottants, ainsi que la taille de
l'exposant, la taille de la mantisse, et la représentation de
l'exposant.) Ça facilite légèrement (très légèrement, en fait)
l'écriture, et rend la lecture beaucoup plus compliquée.

Ensuite quand je veux relire le fichier, je commence par lire
la taille des types et je m'adapte... Qu'en penses tu ?


Que c'est beaucoup de complications pour rien, et que ça ne
résoud toujours pas tous les problèmes.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34



Avatar
James Kanze
On Nov 7, 11:09 pm, Loïc Joly
wrote:

Pour la place, c'est négligeable, mais ça se discute. Cela
dépend de la base de données et aussi de ce que tu ferais en
binaire.


Si tu dois gérer des giga octets ou des terra octets de données, la
place n'est pas négligeable...


Si tu dois communiquer une quantité de données importantes sur
un reseau lent non plus.

C'est une optimisation d'utiliser le binaire. Comme toutes les
optimisations, il vaut mieux s'en passer, mais quand il le faut,
il le faut.

Pour l'instant, Marc ne nous a pas donné assez d'informations
pour supposer qu'il le faut. Et comme pour toutes les
optimisations, en fait, il le faut bien moins souvent qu'on ne
le pense.

En général, si
on utilise le binaire, c'est pour concilier place et vitesse, ça supp ose
donc qu'on étudie chaque champ, ses valeurs minimum et maximum, et do nc
de ne pas se contenter d'écrire des int. Et pour la portabilité,
endianess, encodage et autre joyeusetés seront de la fête tôt ou tard...
tout un poême pour en tirer un avantage notable par rapport au mode t exte !

Pour le temps machine sur la conversion, c'est négligeable aussi, et
même quasi-insignifiant si on lit les données sur un flux lent (à
l'échelle d'un programme C++, même les plus rapides des disque dû rs
fournissent des flux lents, une connexion réseau aussi).

Mais tout ça, à l'ère du XML/HTML à outrances avec plus de tags que de
données, c'est du pinaillage...


Je dirais plutôt qu'utiliser de l'XML là où les performances compte nt
est une ânerie.


Certains ôterait même le « où les performance comptent »:-).
Mais il y a bien de possibilités entre un binaire hautement
optimisé pour la taille et de l'XML.

Je vois un avantage non cité à un format binaire, c'est qu'il
est facile d'avoir un jeu de donnée où la taille est homogène,
ce qui permet de se déplacer rapidement dans le fichier sans
avoir à tout en lire ou à l'indexer.


Ce n'est pas plus difficile avec le texte : tu as certainement
entendu parler de std::setw:-). (En fait, nous utilisons ici des
fichiers texte dont les longueurs de ligne et les tailles de
chaque champs dans la ligne sont fixes, précisemment afin de
pouvoir faire des accès aléatoire.)

Il n'empêche que j'utilise de préférence des formats textes,
mais le binaire a quelques avantages.


Je dirais pas tellement qu'il a des avantages, mais que quelque
fois, il y a des contraintes qui le rendent nécessaire.

--
James Kanze (GABI Software) email:
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


Avatar
Fabien LE LEZ
On Thu, 08 Nov 2007 09:01:03 -0000, James Kanze
:

j'ai bien vu des protocols où il y avait
un drapeau dans l'en-tête du buffer pour dire s'ils étaient
grand-boutien ou petit.


Je crois me souvenir que c'est aussi le cas du format TIFF (images).

Avatar
Ael Rowan Terence
"Fabien LE LEZ" a écrit dans le message de
news:
On Tue, 6 Nov 2007 14:18:00 +0100, "Marc G" :

char const* contents=UneChaine.data();
output.write((char*)&len,sizeof(std::size_t));


Résultat indéfini : les octets seront bien écrits, mais on ne sait pas
dans quel ordre.



Mais une chose me surprend, pourquoi attacher tant d'importance à l'ordre
des des octets, tout en ignorant l'ordre des bits ?


Avatar
Fabien LE LEZ
On Fri, 9 Nov 2007 10:24:58 +0100, "Ael Rowan Terence" :

Mais une chose me surprend, pourquoi attacher tant d'importance à l'ordre
des des octets, tout en ignorant l'ordre des bits ?


Parce que l'octet est l'unité de base dès qu'on parle de fichiers .?

Avatar
Marc Boyer
On 2007-11-09, Ael Rowan Terence wrote:

"Fabien LE LEZ" a écrit dans le message de
news:
On Tue, 6 Nov 2007 14:18:00 +0100, "Marc G" :

char const* contents=UneChaine.data();
output.write((char*)&len,sizeof(std::size_t));


Résultat indéfini : les octets seront bien écrits, mais on ne sait pas
dans quel ordre.



Mais une chose me surprend, pourquoi attacher tant d'importance à l'ordre
des des octets, tout en ignorant l'ordre des bits ?


Parce que l'ordre des bits n'est pas accessible, ou, si tu préfères,
n'existe pas, ou encore, est déjà traité de manière portable par
le matériel...

Sur le disque, je serais très étonné que les bits soient réellement
écris les uns à la suite des autres. Sur le réseau, on envoie souvent
les bits par paquets. Dans la mémoire, je ne sais pas trop, et sur les
bus, ils sont souvent les uns à côté des autres.

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)



1 2 3 4