OVH Cloud OVH Cloud

problèmes avec les streams

19 réponses
Avatar
Frédéric Gourul
Bonjour à tous,

Je patauge lamentablement avec les streams. J'ai beau chercher avec mon ami
google et dans les archives du groupe, je ne parvient pas à en avoir une
vision clair.

A partir de la classe suivante:

class Test
{
public:
void put(const std::string& s);
void put(const char* buf, size_t buflen);
size_t get(std::string& s) const;
size_t get(char* buf) const;
};

Je voudrai créer une classe dérivée de ???stream pour pouvoir convertir les
données
récupérées enregistrement par enregistrement de ma classe pour les convertir
en flux et vice-versa.

J'ai essayé de m'inspirer de l'example de la FAQ, mais il n'utilise pas de
tampon et
je n'ai pas de fonction membre travaillant caractère par caractère. D'après
ce que
je vois, la gestion de tampon est completement pris en charge par streambuf,
mais
je ne sais pas comment la mettre en oeuvre.

Si quelqu'un ici pouvait mettre sur la voie et me montrer un exemple tous
simple de
ce qu'il faut faire, je suis preneur :)

Merci de votre aide.

10 réponses

1 2
Avatar
Jeremie Fouche
Frédéric Gourul a écrit dans le message :
cg47s9$uuh$
Bonjour à tous,

Je patauge lamentablement avec les streams. J'ai beau chercher avec mon
ami

google et dans les archives du groupe, je ne parvient pas à en avoir une
vision clair.

A partir de la classe suivante:

class Test
{
public:
void put(const std::string& s);
void put(const char* buf, size_t buflen);
size_t get(std::string& s) const;
size_t get(char* buf) const;
};

Je voudrai créer une classe dérivée de ???stream pour pouvoir convertir
les

données
récupérées enregistrement par enregistrement de ma classe pour les
convertir

en flux et vice-versa.


quelque chose du genre ( inspiré d'explications de J. Kanze ) :
ATTENTION, Le code suivant n'est pas testé, et il s'appuie sur filebuf,
plutot que sur streambuf qui était demandé, mais l'idée reste la même.

class testStream : public std::ios
{
protected:
testStream() { }

public:
class sentry
{
public:
sentry(testStream& rts) : m_rTestStream(rts) { }

public:
operator bool() const
{
return !m_rTestStream.fail();
}

protected:
testStream& m_rTestStream;
}

protected:
std::filebuf m_filebuf;
};

class iTestStream : public testStream
{
};

class oTestStream : public testStream
{
public:
explicit oTestStream(const char* sNomFichier)
{
m_filebuf.open(sNomFichier,
ios_base::out|ios_base::trunc|ios_base::binary);
init(&m_filebuf);
}
};

il ne reste plus qu'a creer les operateurs de flux :

oTestStream& operator <<(oTestStream& ots, const Test& rcTest)
{
...
}

qui s'appuira tres probablement sur des operateurs de flux de type de base
a creer bien evidement ):

oTestStream& operator <<(oTestStream& ots, unsigned int val)
{
testStream::sentry(ots);
if (sentry)
{
int shift=0;
while (ots && (shift<32))
{
if (oms.rdbuff()->sputc( (val>>shift)&0xFF ) == EOF)
{
ots.clear(ios::badbit);
{
shift += 8;
}
}
return ots;
}

J'espere que ca peut t'aider.

--
Jérémie

Avatar
Samuel Krempp
le Friday 20 August 2004 09:02, écrivit :

Je voudrai créer une classe dérivée de ???stream pour pouvoir convertir
les données
récupérées enregistrement par enregistrement de ma classe pour les
convertir en flux et vice-versa.


Je ne sais pas si ça avance à qque chose dans ton cas de dériver stream..
(vu que l'operator<< n'est pas virtual, tu devras de tte façon utiliser la
classe directement, donc pas de raison de dériver)

La description de but correspond au rôle de formattage donné à l'operator :
oprator<<( stream&, const Test&)

qu'il suffit de surcharger pour obtenir ce que tu veux.

Si c'est de la persistence (aka "sérialisation") que tu veux faire, dans ce
cas tu pourrais effectivement faire une classe à part entière, mais sans
rapport avec stream (enfin, on peut choisir de lui faire utiliser
l'operator<<..)

Sinon, boost contient une lib de serialisation (qui permet de rendre une
classe sérialisable en lui ajoutant une petite fonction membre), si tes
besoins en persistence sont susceptibles de se développer tu pourrais y
jeter un oeil plutôt que de te lancer dans ta propre sérialisation à la
main.
et même si ya juste Test que tu auras besoin de sérialiser, c'est peut être
aussi rapide d'utiliser directement boost::serialization.

--
Sam

Avatar
Frédéric Gourul
"Samuel Krempp" a écrit dans le
message de news: 4125bca9$0$13683$

La description de but correspond au rôle de formattage donné à l'operator
:

oprator<<( stream&, const Test&)


Vu que je ne maitrise pas du tout les streams, j'ai du partir sur la
mauvaise piste.
Je vais donc préciser un peu ce que je veux faire.

J'ai plusieurs classe qui implémentent différent format de fichier, elles
dérives toutes d'une base unique et ont en commun la capacité de lire et
d'écrire des enregistrements texte, chacune effectuant les transformation
nécéssaire pour son format spécifique. J'ai déja défini l'operateur ostream&
operator<<(ostream&, const File&) pour transférer mes fichiers vers un
ostream&...

Ce que je voudrai, c'est dématérialiser le contenu de mes fichiers en flux
(suite d'enregistrement texte) pour pouvoir les convertir vers un autre
format dérivé de File ou même une autre classe sachant manipuler des flux
(genre une classe pour transferer les données via le réseau, une socket
quoi...)

Du coup j'imagine un truc ou je pourrai faire ce genre de choses:

FileFormat1 f1;
FileFormat2 f2;

FileStream fs1(f1);
FileStream fs2(f2);

fs1 << fs2; // copie de f2 dans f1 (au format définit par f1)

Socket sock;
SockStream ss(sock);
ss << fs1; // transfert de f1 sur la socket sock
fs2 << ss; // enregistrement des données de sock dans f2


Voilà en gros ce que je veux faire. Je ne suis pas certain de la sémantique
à donner à mes objets vu que je ne maitrise pas bien tout ca, mais le
principe c'est de dématérialiser les données en un format pouvant être
traité par tout le monde (indépendement du format d'origine et du format
d'arrivé).

Quelle est (sont) la (les) solution(s) pour réaliser ceci...
Merci.

PS: je n'utilise pas boost...

Avatar
Samuel Krempp
le Friday 20 August 2004 14:41, écrivit :

Ce que je voudrai, c'est dématérialiser le contenu de mes fichiers en flux
(suite d'enregistrement texte) pour pouvoir les convertir vers un autre
format dérivé de File ou même une autre classe sachant manipuler des flux
(genre une classe pour transferer les données via le réseau, une socket
quoi...)


ça correspond précisément au rôle des streams C++ : généralisation des flux
divers.


Du coup j'imagine un truc ou je pourrai faire ce genre de choses:

FileFormat1 f1;
FileFormat2 f2;

FileStream fs1(f1);
FileStream fs2(f2);

fs1 << fs2; // copie de f2 dans f1 (au format définit par f1)


par contre, là ce n'est plus vraiment l'approche habituelle en C++.
Ca me semble plutôt être de la sérialisation.

la philosophie C++ est de mettre au niveau stream la gestion du flux de
donnée elle même, pas la signification éventuelle que ça peut avoir. Un
stream n'a habituellement pas les moyens d'interpreter ce qu'il transmet..
(et donc ne peut pas le convertir vers une autre interpretation).
En gros, le stream est là pour encapsuler le média de transmission.

Son rôle n'est *pas* de définir un format de données.
Quand on écrit
MonObj monobj;
cout << monobj;
C'est pas le stream qui formatte, mais un opérateur de formattage
operator<< (stream&, Truc), qui combinent les services de locale à ceux des
streams.
-La locale sait convertir plein de choses en caractères lisibles selon
différents paramètres,
-le streambuf (dans le stream) sait envoyer ces caractères à destination
(pour les operator<< qu'on écrit pour des classes perso, on utilise la
locale indirectement, en appelant des operator<<(stream&, int), etc !)

Bien sûr les 2 ne sont pas tout à fait orthogonaux. Le formattage se fait
différement selon certains paramètres, le seul endroit pratique où les
stocker, c'est dans l'objet stream.

C'est ce qui justifie la classe stream, au dessus du streambuf.
un stream est formé
1.d'un streambuf (le flux lui même, avec uniquement des fonctions pour
envoyer/recevoir des octets, par blocs selon comme convient au media, et
éventuellement avancer/reculer si ça a un sens pour le media)
2. d'une annexe, avec une sorte de consigne (à bagages) où les utilisateurs
du stream (i.e. les operator<<) peuvent stocker les paramètres dont ils
auront besoin au cours de l'utilisation du stream.

Cette consigne se trouve dans la couche ios_base dont dérive chaque stream.
On y trouve les paramètres de précision, de locale, de padding .. dont le
stream lui même n'a rien à faire. C'est mis là pour ses utilisateurs (les
operator<< ...)
C'est vraiment une consigne car n'importe qui peut y stocker ce qu'il veut
(cf ios_base::xalloc) en plus de ces paramètres standards.

Ce système des streams C++ est bien fait, mais c'est vrai qu'on mets du
temps avant de comprendre comment tout ça s'empile, collabore avec locale,
et est censé s'utiliser. Avec cette métaphore de la consigne, j'espère que
tu cerneras le découpage subtile entre locale, stream, et streambuf plus
facilement..

En conclusion, dériver de stream ne sert donc que si c'est nécessaire pour
tirer profit d'un type de streambuf particulier. Pas à implémenter un
format de données différent..

Socket sock;
SockStream ss(sock);
ss << fs1; // transfert de f1 sur la socket sock
fs2 << ss; // enregistrement des données de sock dans f2


Comme je le disais, ce n'est pas dans l'esprit des streams C++.

Je te conseille plutôt de placer l'information de format au niveau des
classes des objets que tu vas faire passer dans tes streams.
(par exple, au niveau des operator<<(stream&, MaClasse) )

L'idiome classique pour copier un flux d'objets vers un autre est alors :
MaClasse obj;
stream1 >> obj;
stream2 << obj;

(si les flux contiennent une liste de trucs, l'idiome tient toujours, avec
MaClasse étant un container de trucs)

Si on ne sait pas quels objets sont dans le flux, alors il n'y rien d'autre
à faire que transferer les octets bruts.
Ca devient donc un probleme de sérialization : on a une famille d'objets
qu'on veut pouvoir envoyer et récuperer dans un flux.

Donc le mieux est d'utiliser boost::serialization, pour bénéficier des mois
de travail sur le sujet sans effort (ou tres peu)
(par exemple, si il y a plusieurs formats différents possible, la question
se pose de savoir à quel niveau placer le choix..
boost::serialization a prévu tout ça en pesant longuement le pour et le
contre !)

PS: je n'utilise pas boost...


ben c'est très dommage !
boost::serialization me semble la meilleure solution pour tes besoins.

--
Sam

Avatar
Frédéric Gourul
"Samuel Krempp" a écrit dans le
message de news: 41261843$0$26980$
le Friday 20 August 2004 14:41, écrivit :


la philosophie C++ est de mettre au niveau stream la gestion du flux de
donnée elle même, pas la signification éventuelle que ça peut avoir. Un
stream n'a habituellement pas les moyens d'interpreter ce qu'il transmet..
(et donc ne peut pas le convertir vers une autre interpretation).
En gros, le stream est là pour encapsuler le média de transmission.


oui, je suis d'accord...

Son rôle n'est *pas* de définir un format de données.
Quand on écrit
MonObj monobj;
cout << monobj;
C'est pas le stream qui formatte, mais un opérateur de formattage
operator<< (stream&, Truc), qui combinent les services de locale à ceux
des

streams.


Ce n'était pas mon intention. Mes classes savent formatter leur contenu en
chaine de texte standard (get) et prendre une chaine de texte pour
l'enregistrer dans le format du fichier (put).

C'est ce qui justifie la classe stream, au dessus du streambuf.
un stream est formé
1.d'un streambuf (le flux lui même, avec uniquement des fonctions pour
envoyer/recevoir des octets, par blocs selon comme convient au media, et
éventuellement avancer/reculer si ça a un sens pour le media)
2. d'une annexe, avec une sorte de consigne (à bagages) où les
utilisateurs

du stream (i.e. les operator<<) peuvent stocker les paramètres dont ils
auront besoin au cours de l'utilisation du stream.


J'ai l'impression que c'est ca que j'ai besoin d'utiliser. J'imaginais un
OFileStream et IFileStream qui utiliseraient les primitives get et set de
mes objets fichier en redéfinissant overflow et underflow (comme dans
l'example de la FAQ). La seule chose c'est que ces fonctions travaillent par
caractères et moi je lit/écrit par blocs...

Ce système des streams C++ est bien fait, mais c'est vrai qu'on mets du
temps avant de comprendre comment tout ça s'empile, collabore avec locale,
et est censé s'utiliser. Avec cette métaphore de la consigne, j'espère que
tu cerneras le découpage subtile entre locale, stream, et streambuf plus
facilement..


J'espère y arriver un jour... :)

En conclusion, dériver de stream ne sert donc que si c'est nécessaire pour
tirer profit d'un type de streambuf particulier. Pas à implémenter un
format de données différent..


ben justement, je voudrai utiliser un streambuf déja existant, le truc qui
me gererait la transmission/récupération des octets sur le flux et
appellerai les fonctions get/put des mes objets fichiers uniquement lorsque
le tampon est vide/plein.

Je te conseille plutôt de placer l'information de format au niveau des
classes des objets que tu vas faire passer dans tes streams.
(par exple, au niveau des operator<<(stream&, MaClasse) )

L'idiome classique pour copier un flux d'objets vers un autre est alors :
MaClasse obj;
stream1 >> obj;
stream2 << obj;


Cette sémantique me convient, mais quel est le type du stream ? std::ostream
?

Si on ne sait pas quels objets sont dans le flux, alors il n'y rien
d'autre

à faire que transferer les octets bruts.
Ca devient donc un probleme de sérialization : on a une famille d'objets
qu'on veut pouvoir envoyer et récuperer dans un flux.


Ce n'est que du texte séparé par un délimiteur d'enregistrement (std::endl).
Je n'ai donc pas l'impression qu'il s'agisse d'un problème de sérialisation.


PS: je n'utilise pas boost...
ben c'est très dommage !

boost::serialization me semble la meilleure solution pour tes besoins.


Je ne nie pas les qualités de cette bibliothèque, loin de là...

merci pour ton aide.


Avatar
kanze
"Jeremie Fouche" wrote in message
news:<cg49mq$3a8$...
Frédéric Gourul a écrit dans le message :
cg47s9$uuh$

Je patauge lamentablement avec les streams. J'ai beau chercher avec
mon ami google et dans les archives du groupe, je ne parvient pas à
en avoir une vision clair.

A partir de la classe suivante:

class Test
{
public:
void put(const std::string& s);
void put(const char* buf, size_t buflen);
size_t get(std::string& s) const;
size_t get(char* buf) const;
};

Je voudrai créer une classe dérivée de ???stream pour pouvoir
convertir les données récupérées enregistrement par enregistrement
de ma classe pour les convertir en flux et vice-versa.


quelque chose du genre ( inspiré d'explications de J. Kanze ) :


Il faudrait d'abord savoir exactement ce qu'il veut. Je vois trois
possibilités :

- Il veut simplement que les << et les >> fonctionnent avec sa classe
comme ils fonctionnent avec toute la reste. Dans ce cas-là, il n'a
qu'à écrire des surcharges d'opérateur qui vont, soit en se basant
sur des operateurs << et >> existants, soit en accédant au streambuf
géré par le flux.

- Il veut que sa classe sert de source ou de destination des données
formattées par ailleurs. Dans ce cas-là, il doit hériter de
streambuf, avec éventuellement un héritage de istream et de ostream
pour fournir des constructeurs de commodité. C'est assez facile,
mais c'est vrai que je ne connais pas beaucoup de littérature sur le
sujet.

- Il veut définir un autre type de formattage, peut-être binaire, pour
ses flux. C'est là, je crois, le problème que tu as essayé à
résoudre ; en tout cas, tu as commencé correctement en dérivant de
std::ios.

ATTENTION, Le code suivant n'est pas testé, et il s'appuie sur
filebuf, plutot que sur streambuf qui était demandé, mais l'idée reste
la même.


Sauf que...

class testStream : public std::ios
^^^^^^^^


std::ios contient déjà un std::streambuf*, auquel tu accèdes au moyen de
la fonction rdbuf().

{
protected:
testStream() { }

public:
class sentry
{
public:
sentry(testStream& rts) : m_rTestStream(rts) { }

public:
operator bool() const
{
return !m_rTestStream.fail();
}

protected:
testStream& m_rTestStream;
}

protected:
std::filebuf m_filebuf;


En aucun cas. Dans la pratique, tu vas utiliser le streambuf* que te
donnes ios. La seule chose, c'est qu'il faut que tu prévois les
constructeurs pour le passer au constructeur de ios.

};

class iTestStream : public testStream
{
};

class oTestStream : public testStream
{
public:
explicit oTestStream(const char* sNomFichier)
{
m_filebuf.open(sNomFichier,
ios_base::out|ios_base::trunc|ios_base::binary);
init(&m_filebuf);
}
};


Je verrai ça dans une classe dérivée, ofTestStream, ou quelque chose du
genre.

Pour la reste, je crois que tu as saisi l'idée, mais je ne suis pas du
tout sûr que c'est ça son problème.

--
James Kanze GABI Software http://www.gabi-soft.fr
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
Samuel Krempp
le Friday 20 August 2004 18:02, écrivit :


En conclusion, dériver de stream ne sert donc que si c'est nécessaire
pour tirer profit d'un type de streambuf particulier. Pas à implémenter
un format de données différent..


ben justement, je voudrai utiliser un streambuf déja existant, le truc qui
me gererait la transmission/récupération des octets sur le flux et
appellerai les fonctions get/put des mes objets fichiers uniquement
lorsque le tampon est vide/plein.


ah bon, j'ai été induit en erreur par le mot "enregistrements" du poste
original puis

FileFormat1 f1;
FileFormat2 f2;

FileStream fs1(f1);
FileStream fs2(f2);


Qu'est ce que ces FileFormat alors ?

je ne comprends pas le problème, et pourquoi tu n'utilises pas les classes
streams / streambuf standard..

--
Sam


Avatar
Samuel Krempp
le Friday 20 August 2004 18:02, écrivit :


En conclusion, dériver de stream ne sert donc que si c'est nécessaire
pour tirer profit d'un type de streambuf particulier. Pas à implémenter
un format de données différent..


ben justement, je voudrai utiliser un streambuf déja existant, le truc qui
me gererait la transmission/récupération des octets sur le flux et
appellerai les fonctions get/put des mes objets fichiers uniquement
lorsque le tampon est vide/plein.


ah bon, j'ai été induit en erreur par le mot "enregistrements" du poste
original puis

FileFormat1 f1;
FileFormat2 f2;

FileStream fs1(f1);
FileStream fs2(f2);


Qu'est ce que ces FileFormat alors ?

je ne comprends pas le problème, et pourquoi tu n'utilises pas les classes
streams / streambuf standard..

En gros tu veux utiliser un streambuf de fichier perso plutot que
std::filebuf ?

--
Sam


Avatar
James Kanze
"Frédéric Gourul" writes:

|> "Samuel Krempp" a écrit
|> dans le message de news: 4125bca9$0$13683$

|> > La description de but correspond au rôle de formattage donné à
|> > l'operator :
|> > oprator<<( stream&, const Test&)

|> Vu que je ne maitrise pas du tout les streams, j'ai du partir sur la
|> mauvaise piste. Je vais donc préciser un peu ce que je veux faire.

|> J'ai plusieurs classe qui implémentent différent format de fichier,
|> elles dérives toutes d'une base unique et ont en commun la capacité
|> de lire et d'écrire des enregistrements texte, chacune effectuant
|> les transformation nécéssaire pour son format spécifique.

Je ne suis toujours pas sûr d'avoir compris. Ces formats, est-ce qu'ils
encodent les mêmes choses, ou est-ce qu'ils sont vraiment indépendants
les uns des autres. Et quel rapport est-ce qu'ils ont avec le texte --
je vois bien ce genre de chose avec, par exemple, des images (qui
peuvent être en gif, jpeg, etc.), mais alors, je ne vois pas où une
représentation texte y entre.

Dans le cas des images, j'imaginerais un format interne unique ; c'est
les classes dérivées de ton FileFormat qui s'occupe chaque fois de
convertir de et vers ce format interne.

Dans ce cas-là, je verrais bien la réutilisation des streambuf pour
effectuer les entrées/sorties ; comme ios, la classe de base
contiendrait un streambuf* qu'il met à la disposition des classes
dérivées. En revanche, étant donné que typiquement, chaque fichier va
servir pour un seul objet, je ne sais pas si je ferais des operator<< et
.



|> J'ai déja défini l'operateur ostream& operator<<(ostream&, const
|> File&) pour transférer mes fichiers vers un ostream&...

Tu veux dire, pour les formatter en format texte. Mais il reste que je
ne vois pas le rapport. D'après ce que j'ai compris, tes FileFormat
s'occupe déjà du formattage. Or, la rôle de ostream, c'st bien le
formattage ; s'il s'agit de sortir des données déjà formattées, c'est le
streambuf qu'il te faut, et non le ostream.

|> Ce que je voudrai, c'est dématérialiser le contenu de mes fichiers
|> en flux (suite d'enregistrement texte) pour pouvoir les convertir
|> vers un autre format dérivé de File ou même une autre classe sachant
|> manipuler des flux (genre une classe pour transferer les données via
|> le réseau, une socket quoi...)

Dans la mésure où tu as un format interne canonique, ça se fait de soi.
Tu lis d'un format, ce qui donne le format canonique, que tu écris vers
un autre format.

|> Du coup j'imagine un truc ou je pourrai faire ce genre de choses:

|> FileFormat1 f1;
|> FileFormat2 f2;

|> FileStream fs1(f1);
|> FileStream fs2(f2);

|> fs1 << fs2; // copie de f2 dans f1 (au format définit par f1)

Je ne suis pas sûr que ça va, dans ton cas. Si le « formattage » est un
fait un simple transcodage, ou s'il s'agit des simples ajouts ou des
suppressions de texte, on peut le faire dans un streambuf filtrant --
dans ce cas-là, on peut très bien écrire :

dest << source.rdbuf() ;

Mais les streambuf filtrants ne peuvent pas vraiment faire du
formattage, puisqu'ils agissent directement sur le flux de caractères,
et non sur les objets parsés ou à formatter. À titre d'exemple, je m'en
sers en sortie pour remplacer des tabs par les espaces, ou en entrée
pour supprimer des commentaires ; on pourrait aussi s'en servir pour le
cryptage ou la compression. Mais ce n'est pas ce que j'appelerai du
formattage. Un streambuf filtrant en sortie pourrait faire du
formattage, mais seulement du formattage texte (indentations, etc.). Il
ne pourrait jamais, en revanche, influer sur le formattage d'un double,
parce qu'il n'intervient qu'après ce formattage est fini.

|> Socket sock;
|> SockStream ss(sock);
|> ss << fs1; // transfert de f1 sur la socket sock
|> fs2 << ss; // enregistrement des données de sock dans f2

|> Voilà en gros ce que je veux faire.

Mais ça, c'est tout à fait autre chose. Un SockStream, typiquement, se
baserait sur istream et ostream pour le formattage ; en fait,
typiquement, tout ce qu'il ajoutera à istream et ostream (dont il
dérivera), ce sont des constructeurs et des destructeurs propre à créer
et à détruire le streambuf qu'il faut (un SockStreamBuf). Toute la
spécialisation pour faire des entrées/sorties sur socket, plutôt que sur
fichier, se trouveront dans le streambuf. Et tout le formattage
s'effectuera dans istream et ostream, sans savoir en fait que la source
ou la destination est un socket.

|> Je ne suis pas certain de la sémantique à donner à mes objets vu que
|> je ne maitrise pas bien tout ca, mais le principe c'est de
|> dématérialiser les données en un format pouvant être traité par tout
|> le monde (indépendement du format d'origine et du format d'arrivé).

Un format canonique interne. On revient à ce que je croyais que tu
démandais au départ.

|> Quelle est (sont) la (les) solution(s) pour réaliser ceci... Merci.

|> PS: je n'utilise pas boost...

Est-ce que tu pourrais ? Parce que si la solution y existe, c'est bien
plus facile à utiliser quelque chose d'existant que de réinventer la
roue.

--
James Kanze
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
Frédéric Gourul
"James Kanze" a écrit dans le message de news:


Je ne suis toujours pas sûr d'avoir compris. Ces formats, est-ce qu'ils
encodent les mêmes choses, ou est-ce qu'ils sont vraiment indépendants
les uns des autres. Et quel rapport est-ce qu'ils ont avec le texte --
je vois bien ce genre de chose avec, par exemple, des images (qui
peuvent être en gif, jpeg, etc.), mais alors, je ne vois pas où une
représentation texte y entre.


Effectivement ce n'est pas clair, et c'est principalement lié à ma totale
ignorance de streams c++. J'ai fait l'impasse de toute cette partie lors de
mon apprentissage (tellement de chose à apprendre et si peu de temps pour le
faire...). Je vais donc combler cette lacune en étudiant cela. Je pense que
je pourrais mieux voir ce dont j'ai besoin et ainsi poser utlérieurement des
questions plus claires. Merci quand même de vous être penché sur le
problème.

Juste pour expliquer: les formats de fichier en question ne définissent pas
le contenu, juste la manière dont sont enregistrés les informations
(longueur fixe sans séparateur, longueur variable avec caractère séparateur,
longueur d'enregistrement en préfixe, etc...).

Mais ça, c'est tout à fait autre chose. Un SockStream, typiquement, se
baserait sur istream et ostream pour le formattage ; en fait,
typiquement, tout ce qu'il ajoutera à istream et ostream (dont il
dérivera), ce sont des constructeurs et des destructeurs propre à créer
et à détruire le streambuf qu'il faut (un SockStreamBuf). Toute la
spécialisation pour faire des entrées/sorties sur socket, plutôt que sur
fichier, se trouveront dans le streambuf. Et tout le formattage
s'effectuera dans istream et ostream, sans savoir en fait que la source
ou la destination est un socket.


Je commence à y voir plus clair, et c'est à cette conclusion que je suis
arrivé ce week-end. La séparation entre la famille des ostream et des
streambuf n'était pas très clair pour moi. Pour lire/écrire sur le média
(socket), je doit dériver de streambuf et faire quelque chose qui ressemble
à filebuf pour les socket. Pour pouvoir utiliser les opérateurs de flux (<<
et >>) c'est un ostream/istream que je dois utiliser. Il me reste à associer
les deux pour créer mes classes de stream:

Si j'ai bien compris, ca donnerait quelque chose comme:

class OSockStream : public SockBuf, public std::ostream {...}
class ISockStream : public SockBuf, public std::istream {...}

et les utiliser comme ceci:

Socket sock;
OSockStream ss(sock);
std::string str = "...";
ss << str;

Le tout, ca va être d'écrire la classe SockBuf... c'est là où j'aurais
probablement besoin d'aide.

Pour mes classes de fichier, je n'ai pas besoin de streambuf, car en fait,
ces classes s'occupent déja des opérations de lecture/écriture sur le média.
Ce sont des classes héritée d'un passé C, j'ai juste encapsulée les
fonctions dans des classes (elles utilisent fread/fwrite pour lire/écrire
sur le fichier).


|> PS: je n'utilise pas boost...

Est-ce que tu pourrais ? Parce que si la solution y existe, c'est bien
plus facile à utiliser quelque chose d'existant que de réinventer la
roue.


Je le pourrais à usage personnel, mais déja plus difficilement
professionnellement (j'ai déja du mal à faire mettre à jour mon
compilateur...). Mais j'ai bien l'impression que tout ce que je cherche se
trouve dans la STL, suffit juste que j'apprenne à les utiliser...

Merci à tous :)

1 2