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

Dériver (?) fstream pour obtenir un stream à partir d'autre chose qu'un fichier

4 réponses
Avatar
Yannick Patois
Bonjour,

Je dispose d'une bibliothèque C doté de fonctions "trucopen" "trucclose"
"trucread" et "trucwrite" doté de la même interface et du même
comportement que leurs analogues Unix (http://linux.die.net/man/2/open,
http://linux.die.net/man/2/read, etc.). Elles n'opèrent pas sur un
fichier Unix standard (sinon les fonctions natives suffiraient
évidemment), mais sur un fichier distant au travers d'un protocole
réseau. Je ne crois pas que les seek et quelques autres fonctions du
genre soient implémentées, mais je n'en ai a priori pas besoin (je vais
de toute façon open et lire séquenciellement)

Une application déjà écrite en C++ utilise (bien sûr) ifstream pour
ouvrir et lire des fichiers locaux (et sans doute que j'aurai à faire la
même chose en ofstream). Je voudrais une classe qui se comporte de la
même façon que je puisse poser exactement à la place de la classe
ifstream pour permettre à cette application de faire le même travail
avec un fichier géré par le protocole de ma bibliothèque C.

Je me suis dis, bon, dérivons un (f?)stream, et remplaçons les appels
"open" unix par des appels à ma bibliothèque, etc. Mais là, je suis
assez dépassé. J'ai jeté un oeil à l'implémentation de fstream dans GCC
pour me faire une idée, et franchement, ça me semble très chevelu, et
largement au dessus de ce que je comprend du C++. J'ai cependant eu
l'impression que je devais avant tout fabriquer un stream à partir de
mes fonctions, donc écrire un dérivé de ios_base, mais je reste très
dans le flou...

Par quel bout prendre le problème? Comment faire le plus proprement
possible à partir de mes 4 fonctions C une classe qui réponde aux
besoins énoncés plus haut?

Merci pour toute aide,

Yannick

--
_/ Yannick Patois \___________________________________________________
| web: http://feelingsurfer.net/garp/ | Garp sur irc undernet |
| email: patois@altespace.org | |

4 réponses

Avatar
Marc
Yannick Patois wrote:

Bonjour,

Je dispose d'une bibliothèque C doté de fonctions "trucopen" "trucclose"
"trucread" et "trucwrite" doté de la même interface et du même
comportement que leurs analogues Unix (http://linux.die.net/man/2/open,
http://linux.die.net/man/2/read, etc.). Elles n'opèrent pas sur un
fichier Unix standard (sinon les fonctions natives suffiraient
évidemment), mais sur un fichier distant au travers d'un protocole
réseau. Je ne crois pas que les seek et quelques autres fonctions du
genre soient implémentées, mais je n'en ai a priori pas besoin (je vais
de toute façon open et lire séquenciellement)

Une application déjà écrite en C++ utilise (bien sûr) ifstream pour
ouvrir et lire des fichiers locaux (et sans doute que j'aurai à faire la
même chose en ofstream). Je voudrais une classe qui se comporte de la
même façon que je puisse poser exactement à la place de la classe
ifstream pour permettre à cette application de faire le même travail
avec un fichier géré par le protocole de ma bibliothèque C.

Je me suis dis, bon, dérivons un (f?)stream, et remplaçons les appels
"open" unix par des appels à ma bibliothèque, etc. Mais là, je suis
assez dépassé. J'ai jeté un oeil à l'implémentation de fstream dans GCC
pour me faire une idée, et franchement, ça me semble très chevelu, et
largement au dessus de ce que je comprend du C++. J'ai cependant eu
l'impression que je devais avant tout fabriquer un stream à partir de
mes fonctions, donc écrire un dérivé de ios_base, mais je reste très
dans le flou...

Par quel bout prendre le problème? Comment faire le plus proprement
possible à partir de mes 4 fonctions C une classe qui réponde aux
besoins énoncés plus haut?



Si on regarde comment la bibliothèque est faite, on a istream
construit sur streambuf, et quand on prend le cas particulier
ifstream, il est construit sur filebuf qui dérive de streambuf. Donc
il semblerait raisonnable de commencer par dériver de filebuf (ou
streambuf), c'est là que les fonctions trucopen vont servir, et
ensuite voir comment remonter au niveau istream.

Je n'ai jamais fait ce genre de chose, mais il traîne un certain
nombre d'exemples de filtering streambuf sur internet qui pourraient
aider à se faire un idée de comment ça marche.
Avatar
Jean-Marc Bourguet
Yannick Patois writes:

Par quel bout prendre le problème? Comment faire le plus proprement
possible à partir de mes 4 fonctions C une classe qui réponde a ux besoins
énoncés plus haut?



La FAQ, maintenant inaccessible, contenait un exemple minimaliste. Je le re copie
ici. Boost a une bibliotheque sensee aider a l'ecriture de bufstream,
je ne l'ai jamais utilisee.

#include <stdio.h>
#include <assert.h>

#include <iostream>
#include <streambuf>

// streambuf minimal encapsulant un FILE*
// - utilise les tampons de FILE donc n'a pas de tampon interne en
// sortie et a un tampon interne de taille 1 en entree car l'interface
// de streambuf ne permet pas de faire moins;
// - ne permet pas la mise en place d'un tampon
// - une version plus complete devrait permettre d'acceder aux
// informations d'erreur plus precises de FILE* et interfacer aussi
// les autres possibilites de FILE* (entre autres synchroniser les
// sungetc/sputbackc avec la possibilite correspondante de FILE*)

class FILEbuf: public std::streambuf
{
public:

explicit FILEbuf(FILE* cstream);
// cstream doit etre non NULL.

protected:

std::streambuf* setbuf(char_type* s, std::streamsize n);

int_type overflow(int_type c);
int sync();

int_type underflow();

private:

FILE* cstream_;
char inputBuffer_[1];
};

FILEbuf::FILEbuf(FILE* cstream)
: cstream_(cstream)
{
// le constructeur de streambuf equivaut a
// setp(NULL, NULL);
// setg(NULL, NULL, NULL);
assert(cstream != NULL);
}

std::streambuf* FILEbuf::setbuf(char_type* s, std::streamsize n)
{
// ne fait rien, ce qui est autorise. Une version plus complete
// devrait vraissemblablement utiliser setvbuf
return NULL;
}

FILEbuf::int_type FILEbuf::overflow(int_type c)
{
if (traits_type::eq_int_type(c, traits_type::eof())) {
// la norme ne le demande pas exactement, mais si on nous passe eof
// la coutume est de faire la meme chose que sync()
return (sync() == 0
? traits_type::not_eof(c)
: traits_type::eof());
} else {
return ((fputc(c, cstream_) != EOF)
? traits_type::not_eof(c)
: traits_type::eof());
}
}

int FILEbuf::sync()
{
return (fflush(cstream_) == 0
? 0
: -1);
}

FILEbuf::int_type FILEbuf::underflow()
{
// Assurance contre des implementations pas strictement conformes a la
// norme qui guaranti que le test est vrai. Cette guarantie n'existait
// pas dans les IOStream classiques.
if (gptr() == NULL || gptr() >= egptr()) {
int gotted = fgetc(cstream_);
if (gotted == EOF) {
return traits_type::eof();
} else {
*inputBuffer_ = gotted;
setg(inputBuffer_, inputBuffer_, inputBuffer_+1);
return traits_type::to_int_type(*inputBuffer_);
}
} else {
return traits_type::to_int_type(*inputBuffer_);
}
}

// ostream minimal facilitant l'utilisation d'un FILEbuf
// herite de maniere privee de FILEbuf, ce qui permet de s'assurer
// qu'il est bien initialise avant std::ostream

class oFILEstream: private FILEbuf, public std::ostream
{
public:
explicit oFILEstream(FILE* cstream);
};

oFILEstream::oFILEstream(FILE* cstream)
: FILEbuf(cstream), std::ostream(this)
{
}

// istream minimal facilitant l'utilisation d'un FILEbuf
// herite de maniere privee de FILEbuf, ce qui permet de s'assurer
// qu'il est bien initialise avant std::istream

class iFILEstream: private FILEbuf, public std::istream
{
public:
explicit iFILEstream(FILE* cstream);
};

iFILEstream::iFILEstream(FILE* cstream)
: FILEbuf(cstream), std::istream(this)
{
}

// petit programme de test
#include <assert.h>
int main(int argc, char* argv[])
{
FILE* ocstream = fopen("result", "w");
assert (ocstream != NULL);
oFILEstream ocppstream(ocstream);
ocppstream << "Du texte";
fprintf(ocstream, " melange");
fclose(ocstream);
FILE* icstream = fopen("result", "r");
assert (icstream != NULL);
iFILEstream icppstream(icstream);
std::string word1;
std::string word2;
icppstream >> word1;
icppstream >> word2;
char buf[1024];
fgets(buf, 1024, icstream);
std::cout << "Got :" << word1 << ':' << word2 << ':' << buf << 'n';
}

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index. html
Site de usenet-fr: http://www.usenet-fr.news.eu.org
Avatar
Yannick Patois
Bonjour,

On 04/29/2012 01:41 AM, Marc wrote:
Yannick Patois wrote:
Je dispose d'une bibliothèque C doté de fonctions "trucopen" "trucclose"
"trucread" et "trucwrite" doté de la même interface et du même
comportement que leurs analogues Unix (http://linux.die.net/man/2/open,
http://linux.die.net/man/2/read, etc.). Elles n'opèrent pas sur un
Une application déjà écrite en C++ utilise (bien sûr) ifstream pour
ouvrir et lire des fichiers locaux (et sans doute que j'aurai à faire la
même chose en ofstream). Je voudrais une classe qui se comporte de la
même façon que je puisse poser exactement à la place de la classe
ifstream pour permettre à cette application de faire le même travail
avec un fichier géré par le protocole de ma bibliothèque C.
Par quel bout prendre le problème? Comment faire le plus proprement
possible à partir de mes 4 fonctions C une classe qui réponde aux
besoins énoncés plus haut?



Si on regarde comment la bibliothèque est faite, on a istream
construit sur streambuf, et quand on prend le cas particulier
ifstream, il est construit sur filebuf qui dérive de streambuf. Donc
il semblerait raisonnable de commencer par dériver de filebuf (ou
streambuf), c'est là que les fonctions trucopen vont servir, et
ensuite voir comment remonter au niveau istream.



Merci pour ces précieuses indications.

Yannick


--
_/ Yannick Patois ___________________________________________________
| web: http://feelingsurfer.net/garp/ | Garp sur irc undernet |
| email: | |
| http://www.jean-luc-melenchon.fr/ Le blog de campagne de Mélenchon |
Avatar
Yannick Patois
Bonjour,

On 04/30/2012 09:08 AM, Jean-Marc Bourguet wrote:
Yannick Patois writes:
Par quel bout prendre le problème? Comment faire le plus proprement
possible à partir de mes 4 fonctions C une classe qui réponde aux besoins
énoncés plus haut?


La FAQ, maintenant inaccessible, contenait un exemple minimaliste. Je le recopie
ici.



Ton exemple m'est d'une très grande aide pour comprendre le
fonctionnement d'un stream.

Boost a une bibliotheque sensee aider a l'ecriture de bufstream,
je ne l'ai jamais utilisee.



Je vais aussi y jeter un oeil; mon application utilise déjà Boost.

Merci beaucoup.

Yannick

--
_/ Yannick Patois ___________________________________________________
| web: http://feelingsurfer.net/garp/ | Garp sur irc undernet |
| email: | |
| http://www.jean-luc-melenchon.fr/ Le blog de campagne de Mélenchon |