j'ai cherché sur plusieurs documents et ouvrages de
référence la possibilité ou pas de programmer des
redirections de flux localement à une application C++. Je ne
souhaite pas le faire via le shell, car de telle
redirections sont globales à toute l'application.
Je n'ai pas pris le temps de lire tout le fil mais il me
semble qu'aucune solution qui te convienne n'ait encore été
proposée.
Moi j'utilise parfois celle-ci, peut-être pourra-t-elle t'aider :
#include <iostream>
#include <fstream>
#include <sstream>
class IOredirection
{
private:
std::streambuf* old_in;
std::streambuf* old_out;
std::streambuf* old_err;
std::streambuf* old_log;
public:
IOredirection(void)
{
old_out = std::cout.rdbuf();
old_err = std::cerr.rdbuf();
old_log = std::clog.rdbuf();
old_in = std::cin.rdbuf();
}
~IOredirection(void) { ResetStreams(); }
void setStdOut(std::ostream& out)
{ std::cout.rdbuf(out.rdbuf()); }
void setStdErr(std::ostream& err)
{ std::cerr.rdbuf(err.rdbuf()); }
void setStdLog(std::ostream& log)
{ std::clog.rdbuf(log.rdbuf()); }
void setStdIn(std::istream& in)
{ std::cin.rdbuf(in.rdbuf()); }
void ResetStreams(void)
{
std::cout.rdbuf(old_out);
std::cerr.rdbuf(old_err);
std::clog.rdbuf(old_log);
std::cin.rdbuf(old_in);
}
};
int main(int argc, char **argv)
{
IOredirection io;
std::ofstream out("out.txt"), err("err.txt"), log("log.txt",std::ofstr eam::app);
io.setStdOut(out);
io.setStdErr(err);
io.setStdLog(log);
cout << "dans le fichier out.txt" << endl;
cerr << "dans le fichier err.txt" << endl;
clog << "dans le fichier log.txt" << endl;
//cin >> variable; // lecture depuis le fichier in.txt
}
Bien sûr il n'est pas nécessaire de tout rediriger.
Enfin pour bien faire les choses il faudrait faire de
IOredirection un singleton
mais là ça fonctionne déjà bien, enfin si ça répond à tes
attentes.
Dernière remarque, si tu fais la redirection en cours de
programme il faut sans doute utiliser la version suivante pour
garder tout l'état des flux :
void setStdOut(std::ostream& out)
{
out.copyfmt(std::cout);
out.clear(std::cout.rdstate());
std::cout.rdbuf(out.rdbuf());
}
j'ai cherché sur plusieurs documents et ouvrages de
référence la possibilité ou pas de programmer des
redirections de flux localement à une application C++. Je ne
souhaite pas le faire via le shell, car de telle
redirections sont globales à toute l'application.
Je n'ai pas pris le temps de lire tout le fil mais il me
semble qu'aucune solution qui te convienne n'ait encore été
proposée.
Moi j'utilise parfois celle-ci, peut-être pourra-t-elle t'aider :
#include <iostream>
#include <fstream>
#include <sstream>
class IOredirection
{
private:
std::streambuf* old_in;
std::streambuf* old_out;
std::streambuf* old_err;
std::streambuf* old_log;
public:
IOredirection(void)
{
old_out = std::cout.rdbuf();
old_err = std::cerr.rdbuf();
old_log = std::clog.rdbuf();
old_in = std::cin.rdbuf();
}
~IOredirection(void) { ResetStreams(); }
void setStdOut(std::ostream& out)
{ std::cout.rdbuf(out.rdbuf()); }
void setStdErr(std::ostream& err)
{ std::cerr.rdbuf(err.rdbuf()); }
void setStdLog(std::ostream& log)
{ std::clog.rdbuf(log.rdbuf()); }
void setStdIn(std::istream& in)
{ std::cin.rdbuf(in.rdbuf()); }
void ResetStreams(void)
{
std::cout.rdbuf(old_out);
std::cerr.rdbuf(old_err);
std::clog.rdbuf(old_log);
std::cin.rdbuf(old_in);
}
};
int main(int argc, char **argv)
{
IOredirection io;
std::ofstream out("out.txt"), err("err.txt"), log("log.txt",std::ofstr eam::app);
io.setStdOut(out);
io.setStdErr(err);
io.setStdLog(log);
cout << "dans le fichier out.txt" << endl;
cerr << "dans le fichier err.txt" << endl;
clog << "dans le fichier log.txt" << endl;
//cin >> variable; // lecture depuis le fichier in.txt
}
Bien sûr il n'est pas nécessaire de tout rediriger.
Enfin pour bien faire les choses il faudrait faire de
IOredirection un singleton
mais là ça fonctionne déjà bien, enfin si ça répond à tes
attentes.
Dernière remarque, si tu fais la redirection en cours de
programme il faut sans doute utiliser la version suivante pour
garder tout l'état des flux :
void setStdOut(std::ostream& out)
{
out.copyfmt(std::cout);
out.clear(std::cout.rdstate());
std::cout.rdbuf(out.rdbuf());
}
j'ai cherché sur plusieurs documents et ouvrages de
référence la possibilité ou pas de programmer des
redirections de flux localement à une application C++. Je ne
souhaite pas le faire via le shell, car de telle
redirections sont globales à toute l'application.
Je n'ai pas pris le temps de lire tout le fil mais il me
semble qu'aucune solution qui te convienne n'ait encore été
proposée.
Moi j'utilise parfois celle-ci, peut-être pourra-t-elle t'aider :
#include <iostream>
#include <fstream>
#include <sstream>
class IOredirection
{
private:
std::streambuf* old_in;
std::streambuf* old_out;
std::streambuf* old_err;
std::streambuf* old_log;
public:
IOredirection(void)
{
old_out = std::cout.rdbuf();
old_err = std::cerr.rdbuf();
old_log = std::clog.rdbuf();
old_in = std::cin.rdbuf();
}
~IOredirection(void) { ResetStreams(); }
void setStdOut(std::ostream& out)
{ std::cout.rdbuf(out.rdbuf()); }
void setStdErr(std::ostream& err)
{ std::cerr.rdbuf(err.rdbuf()); }
void setStdLog(std::ostream& log)
{ std::clog.rdbuf(log.rdbuf()); }
void setStdIn(std::istream& in)
{ std::cin.rdbuf(in.rdbuf()); }
void ResetStreams(void)
{
std::cout.rdbuf(old_out);
std::cerr.rdbuf(old_err);
std::clog.rdbuf(old_log);
std::cin.rdbuf(old_in);
}
};
int main(int argc, char **argv)
{
IOredirection io;
std::ofstream out("out.txt"), err("err.txt"), log("log.txt",std::ofstr eam::app);
io.setStdOut(out);
io.setStdErr(err);
io.setStdLog(log);
cout << "dans le fichier out.txt" << endl;
cerr << "dans le fichier err.txt" << endl;
clog << "dans le fichier log.txt" << endl;
//cin >> variable; // lecture depuis le fichier in.txt
}
Bien sûr il n'est pas nécessaire de tout rediriger.
Enfin pour bien faire les choses il faudrait faire de
IOredirection un singleton
mais là ça fonctionne déjà bien, enfin si ça répond à tes
attentes.
Dernière remarque, si tu fais la redirection en cours de
programme il faut sans doute utiliser la version suivante pour
garder tout l'état des flux :
void setStdOut(std::ostream& out)
{
out.copyfmt(std::cout);
out.clear(std::cout.rdstate());
std::cout.rdbuf(out.rdbuf());
}
Dernière remarque, si tu fais la redirection en cours de
programme il faut sans doute utiliser la version suivante
pour garder tout l'état des flux :
void setStdOut(std::ostream& out)
{
out.copyfmt(std::cout);
out.clear(std::cout.rdstate());
std::cout.rdbuf(out.rdbuf());
}
Et aussi la locale, le caractere de remplissage (fill), les
flags de gestion des exceptions, le flux synchronise (tie), et
j'en oublie surement...
Dernière remarque, si tu fais la redirection en cours de
programme il faut sans doute utiliser la version suivante
pour garder tout l'état des flux :
void setStdOut(std::ostream& out)
{
out.copyfmt(std::cout);
out.clear(std::cout.rdstate());
std::cout.rdbuf(out.rdbuf());
}
Et aussi la locale, le caractere de remplissage (fill), les
flags de gestion des exceptions, le flux synchronise (tie), et
j'en oublie surement...
Dernière remarque, si tu fais la redirection en cours de
programme il faut sans doute utiliser la version suivante
pour garder tout l'état des flux :
void setStdOut(std::ostream& out)
{
out.copyfmt(std::cout);
out.clear(std::cout.rdstate());
std::cout.rdbuf(out.rdbuf());
}
Et aussi la locale, le caractere de remplissage (fill), les
flags de gestion des exceptions, le flux synchronise (tie), et
j'en oublie surement...
Michel Decima wrote:
[...]Dernière remarque, si tu fais la redirection en cours de
programme il faut sans doute utiliser la version suivante
pour garder tout l'état des flux :
void setStdOut(std::ostream& out)
{
out.copyfmt(std::cout);
out.clear(std::cout.rdstate());
std::cout.rdbuf(out.rdbuf());
}
Et aussi la locale, le caractere de remplissage (fill), les
flags de gestion des exceptions, le flux synchronise (tie), et
j'en oublie surement...
C'est tout compris dans le copyfmt. Copyfmt copie tout sauf
rdbuf() et rdstate(). Mais à mon avis, il ne faut pas le copier.
Aussi, je n'aime pas du tout le fait qu'une erreur sur out
disparaisse. J'aurais vu une copie de l'état dans l'autre
sens ; qu'une erreur présente sur out apparaisse alors sur
cout. (Mais attention alors de l'ordre des copies ; la
positionnement d'une erreur peut provoquer une exception.)
[Pour la reste, je crois que nos critiques vont dans le même
sens.]
Michel Decima wrote:
[...]
Dernière remarque, si tu fais la redirection en cours de
programme il faut sans doute utiliser la version suivante
pour garder tout l'état des flux :
void setStdOut(std::ostream& out)
{
out.copyfmt(std::cout);
out.clear(std::cout.rdstate());
std::cout.rdbuf(out.rdbuf());
}
Et aussi la locale, le caractere de remplissage (fill), les
flags de gestion des exceptions, le flux synchronise (tie), et
j'en oublie surement...
C'est tout compris dans le copyfmt. Copyfmt copie tout sauf
rdbuf() et rdstate(). Mais à mon avis, il ne faut pas le copier.
Aussi, je n'aime pas du tout le fait qu'une erreur sur out
disparaisse. J'aurais vu une copie de l'état dans l'autre
sens ; qu'une erreur présente sur out apparaisse alors sur
cout. (Mais attention alors de l'ordre des copies ; la
positionnement d'une erreur peut provoquer une exception.)
[Pour la reste, je crois que nos critiques vont dans le même
sens.]
Michel Decima wrote:
[...]Dernière remarque, si tu fais la redirection en cours de
programme il faut sans doute utiliser la version suivante
pour garder tout l'état des flux :
void setStdOut(std::ostream& out)
{
out.copyfmt(std::cout);
out.clear(std::cout.rdstate());
std::cout.rdbuf(out.rdbuf());
}
Et aussi la locale, le caractere de remplissage (fill), les
flags de gestion des exceptions, le flux synchronise (tie), et
j'en oublie surement...
C'est tout compris dans le copyfmt. Copyfmt copie tout sauf
rdbuf() et rdstate(). Mais à mon avis, il ne faut pas le copier.
Aussi, je n'aime pas du tout le fait qu'une erreur sur out
disparaisse. J'aurais vu une copie de l'état dans l'autre
sens ; qu'une erreur présente sur out apparaisse alors sur
cout. (Mais attention alors de l'ordre des copies ; la
positionnement d'une erreur peut provoquer une exception.)
[Pour la reste, je crois que nos critiques vont dans le même
sens.]
A ce propos, je cherche une methode pour reinitialiser
completement les attributs d'un flux (flags, witdh, precision
etc.) pour revenir a l'etat initial (celui du constructeur).
Est ce que l'ecriture
flux.copyfmt(std::ios(NULL));
pourrait correspondre a mon besoin (j'ai un gros doute sur le
parametre NULL) ?
Je sais que ce n'est pas tres "propre", mais la bonne solution
serait de toucher au design, et je ne veut pas le faire tout
de suite, meme si c'est prevu.
Aussi, je n'aime pas du tout le fait qu'une erreur sur out
disparaisse. J'aurais vu une copie de l'état dans l'autre
sens ; qu'une erreur présente sur out apparaisse alors sur
cout. (Mais attention alors de l'ordre des copies ; la
positionnement d'une erreur peut provoquer une exception.)
La derniere fois que j'ai eu a rediriger un flux, j'avais fait
la copie de l'état dans ce sens, pour la raison que tu cites.
Mais je n'avais pas pris en compte le probleme des exceptions
(que je n'ai jamais utilise sur les flux, d'ailleurs).
A ce propos, je cherche une methode pour reinitialiser
completement les attributs d'un flux (flags, witdh, precision
etc.) pour revenir a l'etat initial (celui du constructeur).
Est ce que l'ecriture
flux.copyfmt(std::ios(NULL));
pourrait correspondre a mon besoin (j'ai un gros doute sur le
parametre NULL) ?
Je sais que ce n'est pas tres "propre", mais la bonne solution
serait de toucher au design, et je ne veut pas le faire tout
de suite, meme si c'est prevu.
Aussi, je n'aime pas du tout le fait qu'une erreur sur out
disparaisse. J'aurais vu une copie de l'état dans l'autre
sens ; qu'une erreur présente sur out apparaisse alors sur
cout. (Mais attention alors de l'ordre des copies ; la
positionnement d'une erreur peut provoquer une exception.)
La derniere fois que j'ai eu a rediriger un flux, j'avais fait
la copie de l'état dans ce sens, pour la raison que tu cites.
Mais je n'avais pas pris en compte le probleme des exceptions
(que je n'ai jamais utilise sur les flux, d'ailleurs).
A ce propos, je cherche une methode pour reinitialiser
completement les attributs d'un flux (flags, witdh, precision
etc.) pour revenir a l'etat initial (celui du constructeur).
Est ce que l'ecriture
flux.copyfmt(std::ios(NULL));
pourrait correspondre a mon besoin (j'ai un gros doute sur le
parametre NULL) ?
Je sais que ce n'est pas tres "propre", mais la bonne solution
serait de toucher au design, et je ne veut pas le faire tout
de suite, meme si c'est prevu.
Aussi, je n'aime pas du tout le fait qu'une erreur sur out
disparaisse. J'aurais vu une copie de l'état dans l'autre
sens ; qu'une erreur présente sur out apparaisse alors sur
cout. (Mais attention alors de l'ordre des copies ; la
positionnement d'une erreur peut provoquer une exception.)
La derniere fois que j'ai eu a rediriger un flux, j'avais fait
la copie de l'état dans ce sens, pour la raison que tu cites.
Mais je n'avais pas pris en compte le probleme des exceptions
(que je n'ai jamais utilise sur les flux, d'ailleurs).
Michel Decima wrote:flux.copyfmt(std::ios(NULL));
pourrait correspondre a mon besoin (j'ai un gros doute sur le
parametre NULL) ?
À mon avis, ça doit marcher. NULL est explicitement permis comme
paramètre, avec un effet sur les post-conditions (rdstate()
renvoie badbit, plutôt que goodbit).
Je sais que ce n'est pas tres "propre", mais la bonne solution
serait de toucher au design, et je ne veut pas le faire tout
de suite, meme si c'est prevu.
Je sais même pas ce qu'il y a de malpropre là dedans. Mais c'est
vrai qu'il manque un moyen facile. (Je crois qu'il y en a une
proposition pour la prochaine version de la norme.)
La derniere fois que j'ai eu a rediriger un flux, j'avais fait
la copie de l'état dans ce sens, pour la raison que tu cites.
Mais je n'avais pas pris en compte le probleme des exceptions
(que je n'ai jamais utilise sur les flux, d'ailleurs).
Moi nom plus. Et l'histoire des exceptions peut être genant. A
priori, tu ne veux pas les changer, bien que le copyfmt le fait.
Je crois que la meilleur solution, c'est de sauvegarder l'ancien
état (de la destination), puis les désactiver. Après toutes les
copies, on réstitue l'état initial des exceptions (et si il y
avait une erreur dans la source, et que les exceptions étaient
actives, il y aura une exception).
Michel Decima wrote:
flux.copyfmt(std::ios(NULL));
pourrait correspondre a mon besoin (j'ai un gros doute sur le
parametre NULL) ?
À mon avis, ça doit marcher. NULL est explicitement permis comme
paramètre, avec un effet sur les post-conditions (rdstate()
renvoie badbit, plutôt que goodbit).
Je sais que ce n'est pas tres "propre", mais la bonne solution
serait de toucher au design, et je ne veut pas le faire tout
de suite, meme si c'est prevu.
Je sais même pas ce qu'il y a de malpropre là dedans. Mais c'est
vrai qu'il manque un moyen facile. (Je crois qu'il y en a une
proposition pour la prochaine version de la norme.)
La derniere fois que j'ai eu a rediriger un flux, j'avais fait
la copie de l'état dans ce sens, pour la raison que tu cites.
Mais je n'avais pas pris en compte le probleme des exceptions
(que je n'ai jamais utilise sur les flux, d'ailleurs).
Moi nom plus. Et l'histoire des exceptions peut être genant. A
priori, tu ne veux pas les changer, bien que le copyfmt le fait.
Je crois que la meilleur solution, c'est de sauvegarder l'ancien
état (de la destination), puis les désactiver. Après toutes les
copies, on réstitue l'état initial des exceptions (et si il y
avait une erreur dans la source, et que les exceptions étaient
actives, il y aura une exception).
Michel Decima wrote:flux.copyfmt(std::ios(NULL));
pourrait correspondre a mon besoin (j'ai un gros doute sur le
parametre NULL) ?
À mon avis, ça doit marcher. NULL est explicitement permis comme
paramètre, avec un effet sur les post-conditions (rdstate()
renvoie badbit, plutôt que goodbit).
Je sais que ce n'est pas tres "propre", mais la bonne solution
serait de toucher au design, et je ne veut pas le faire tout
de suite, meme si c'est prevu.
Je sais même pas ce qu'il y a de malpropre là dedans. Mais c'est
vrai qu'il manque un moyen facile. (Je crois qu'il y en a une
proposition pour la prochaine version de la norme.)
La derniere fois que j'ai eu a rediriger un flux, j'avais fait
la copie de l'état dans ce sens, pour la raison que tu cites.
Mais je n'avais pas pris en compte le probleme des exceptions
(que je n'ai jamais utilise sur les flux, d'ailleurs).
Moi nom plus. Et l'histoire des exceptions peut être genant. A
priori, tu ne veux pas les changer, bien que le copyfmt le fait.
Je crois que la meilleur solution, c'est de sauvegarder l'ancien
état (de la destination), puis les désactiver. Après toutes les
copies, on réstitue l'état initial des exceptions (et si il y
avait une erreur dans la source, et que les exceptions étaient
actives, il y aura une exception).
Michel Decima wrote:Est ce que l'ecriture
flux.copyfmt(std::ios(NULL));
pourrait correspondre a mon besoin (j'ai un gros doute sur le
parametre NULL) ?
À mon avis, ça doit marcher. NULL est explicitement permis comme
paramètre, avec un effet sur les post-conditions (rdstate()
renvoie badbit, plutôt que goodbit).
Michel Decima wrote:
Est ce que l'ecriture
flux.copyfmt(std::ios(NULL));
pourrait correspondre a mon besoin (j'ai un gros doute sur le
parametre NULL) ?
À mon avis, ça doit marcher. NULL est explicitement permis comme
paramètre, avec un effet sur les post-conditions (rdstate()
renvoie badbit, plutôt que goodbit).
Michel Decima wrote:Est ce que l'ecriture
flux.copyfmt(std::ios(NULL));
pourrait correspondre a mon besoin (j'ai un gros doute sur le
parametre NULL) ?
À mon avis, ça doit marcher. NULL est explicitement permis comme
paramètre, avec un effet sur les post-conditions (rdstate()
renvoie badbit, plutôt que goodbit).
Michel Decima wrote:Est ce que l'ecriture
flux.copyfmt(std::ios(NULL));
pourrait correspondre a mon besoin (j'ai un gros doute sur
le parametre NULL) ?
À mon avis, ça doit marcher. NULL est explicitement permis
comme paramètre, avec un effet sur les post-conditions
(rdstate() renvoie badbit, plutôt que goodbit).
Haha! ca marche pas! Il semble que le constructeur de copie de
std::ios est privé, et comme l'écriture ci dessus necessite un
temporaire, il faut l'accès au constructeur de copie:
Evidemment, si on ecrit
std::ostringstream flux;
std::ios cleaner(NULL);
flux.copyfmt(cleaner);
ca compile beaucoup mieux.
Michel Decima wrote:
Est ce que l'ecriture
flux.copyfmt(std::ios(NULL));
pourrait correspondre a mon besoin (j'ai un gros doute sur
le parametre NULL) ?
À mon avis, ça doit marcher. NULL est explicitement permis
comme paramètre, avec un effet sur les post-conditions
(rdstate() renvoie badbit, plutôt que goodbit).
Haha! ca marche pas! Il semble que le constructeur de copie de
std::ios est privé, et comme l'écriture ci dessus necessite un
temporaire, il faut l'accès au constructeur de copie:
Evidemment, si on ecrit
std::ostringstream flux;
std::ios cleaner(NULL);
flux.copyfmt(cleaner);
ca compile beaucoup mieux.
Michel Decima wrote:Est ce que l'ecriture
flux.copyfmt(std::ios(NULL));
pourrait correspondre a mon besoin (j'ai un gros doute sur
le parametre NULL) ?
À mon avis, ça doit marcher. NULL est explicitement permis
comme paramètre, avec un effet sur les post-conditions
(rdstate() renvoie badbit, plutôt que goodbit).
Haha! ca marche pas! Il semble que le constructeur de copie de
std::ios est privé, et comme l'écriture ci dessus necessite un
temporaire, il faut l'accès au constructeur de copie:
Evidemment, si on ecrit
std::ostringstream flux;
std::ios cleaner(NULL);
flux.copyfmt(cleaner);
ca compile beaucoup mieux.