Comment déterminer la météo Onetream est un fichier ou un flux de console. Dans le programme suivant, je veux imprimer "Bonjour Fichier!" Tout en écrivant dans un fichier et "Bello Console!" en écrivant à la console. Dans quelle condition dois-je spécifier à la ligne 17?
#include <fstream> #include<iostream> #include <string> using namespace std; class A{ public: A(string msg):_str(msg){} string str()const {return _str;}; private: string _str; }; ostream & operator << (ostream & os, const A & a) { if (os is ofstream) //this is line 17 os << "Hello file! " << a.str() << endl; else os << "Hello console! " << a.str() << endl; return os; } int main() { A a("message"); ofstream ofile("test.txt"); if (!ofile) cerr << "Unable to open file"; else ofile << a; // "Hello file" cout << a << endl; // "Hello console" }
6 Réponses :
Peut-être pas jolie, mais Nous pourrions utiliser & os == & std :: cout code>, mais la sortie standard peut être redirigée vers le fichier, donc je pense que je pense que Il est préférable d'utiliser l'objet Streambuf à la place. (Voir Cette réponse pour une meilleure compréhension quant à la redirection fonctionne et pourquoi la comparaison de Streambuf résout le problème en toute sécurité!) p> p>
Et aussi, devez-vous inclure std :: cerr code> dans l'essai en plus de
std :: cout code>? c'est à dire.
(& OS == & STD :: COUT || & OS == & STD :: CERR) CODE>
Je ne vois aucun problème avec cette approche. Par conséquent, +1.
@Nawaz "Je ne vois aucun problème avec cette approche": sauf, bien sûr que cela ne fonctionne pas. Si la norme OUT a été redirigée vers un fichier, par exemple, il produira toujours "bonjour console!" Code>.
@Jameskanze: hehe. Comme Ce ? J'espère que la puissance ne fait pas ça. De plus, cela peut être corrigé: stocker la mémoire tampon de stdout dans une variable globale cachée i> et comparer cela à la place!
@Jameskanze: J'ai réparé ça. Voir maintenant. :-)
Il y a aussi sabog code> et tous les
w ... code> variantes. Bien qu'ils utilisent probablement les mêmes tampons de flux en dessous.
Ça ne marche toujours pas. MyProg> xxx.txt code> devrait produire `" Bonjour fichier! ", par exemple. (C'est ce que je voulais dire par la redirection, et c'est très très commun.)
@Tobiasbrandt Ils ne peuvent pas utiliser le même streambuf, car dans un cas, le type est std :: streambuf code>, et dans l'autre
std :: wstreambuf code>.
@Jameskanze: C'est une chose différente. MyProg> xxx.txt code> n'est pas contrôlé par
MyProg code> plus, pas au moins par
opérateur <<< / code>.
@Nawaz non, mais c'est tout le point. Sinon, vous pouvez simplement utiliser un drapeau global ou passer un argument supplémentaire. Et c'est très très courant de rediriger la sortie de cette façon; bien plus commun que des choses comme std :: Cout.rdbuf (& AfileBuf); code>.
@Tobiasbrandt oui et non. Un std :: ostream code> ne peut pas pointer sur l'un d'entre eux, de sorte que vous n'avez pas à vous soucier d'eux. Le vrai problème est que
std :: cout code> et
std :: cerr code> peut sortir aux fichiers, en cas de redirection et que
std :: destream code > peut sortir à la fenêtre du terminal, par exemple Si le nom du fichier était
"/ dev / tty" code> (sous UNIX). Le test ne fonctionne tout simplement pas.
@Jameskanze: Tout le point est dans le titre de la question qui dit "discrimination entre fichier et console flux b>" i> et cette solution le fait. :-)
@Nawaz: S'il s'agit de la question du verbatim, ce n'est peut-être pas ce que l'OP s'attend à. La détection du fichier TTY VS n'a pas de sens en soi, en général, il est utilisé pour savoir s'il faut mettre en place des caractères de formatage dans le flux (gras / normal, couleurs, ...) qui ont une signification dans TTY (OS dépendante) mais encombrer un fichier.
@Nawaz et un std :: destream code> ouvert avec
"/ dev / tty" code> est un flux de console, un
std :: istream code> initialisé avec un
STD :: FILEBUF CODE> est un flux de fichiers (ou peut-être ---, il peut également s'agir d'un flux de tuyaux nommé). Et
std :: cout code> peut être un flux de console, un flux de fichiers, un flux de tuyauterie ou beaucoup d'autres choses. Alors, quel est votre point.
Je pense que l'orchestre de la question initiale doit peser sur la manière dont la solution est généralisée. L'approche ci-dessus semble raisonnable si elles veulent simplement couvrir des cas simples, communs et ne se soucient pas vraiment de la redirection. S'ils ont besoin de quelque chose de robuste, vous devez supprimer l'API pour tout système d'exploitation que vous utilisez et écrivez un code spécifique au système d'exploitation.
@Joez "et ne vous souciez pas vraiment de la redirection": Pouvez-vous imaginer un scénario où ce serait le cas? (Au moins sous Windows et Unix. Sur un Mainframe IBM, vous pouvez généralement supposer que tout est un fichier et être fait avec elle.)
@Jameskanze: Dans mon expérience, la redirection ne semble pas vraiment tout ce qui est populaire sous Windows. Comme je l'ai dit, nous faisons preuve d'hypothèses sur le cas d'utilisation. Nous avons besoin de plus d'informations.
@Joez console Windows ne semble pas que populaire en général sous Windows. La plupart des "applications de console" sont réellement invoquées dans un fichier .bat code>, où la redirection est fréquente. (Bien sûr, là sont i> les utilisateurs de Windows comme moi-même, vous avez installé Cygwin et utilisez Bash. Et nous redirigons comme un fou.)
@Joez pas que la fréquence compte. Un programme non interactif qui écrit à std :: cout code> est incorrect s'il ne peut pas sortir correctement dans un fichier. (Mais bien sûr, il change la sortie lorsqu'il est dans un fichier, il est donc difficile de dire ce qu'il fait.)
Vous pouvez (ab) utiliser tellp () code>, qui retourne
-1 code> si le flux n'a pas de position:
bool isConsoleStream(ostream const& stream)
{
return stream.tellp() == -1;
}
Je pense que @kokan approche est précise i>. Et cette approche n'est pas, car cela dépend de la mise en œuvre!
Ce ne est pas. Tell est nécessaire pour renvoyer -1 si le flux ne prend pas en charge le positionnement. Les flux de la console ne peuvent pas prendre en charge le positionnement et les flux de fichiers.
Il peut également y avoir d'autres flux, sans soutirez le positionnement. Ce chèque ne sera donc pas en mesure de distinguer entre std :: cout code> et d'autres flux de ce type.
@Tobiasbrandt et les tuyaux ne supportent pas le positionnement, mais ne sont pas non plus terminaux. Il n'y a pas de réponse précise sans obtenir le niveau système FD (et peut-être même pas alors pour certains systèmes). (Mais même s'il n'est pas précis, c'est probablement assez fiable. Sauf si le code émet une sortie via un flux de filtrage qui ne prend pas en charge la recherche. Comme je fais une grande partie du temps.)
Oui, vous êtes tous les deux corrects. Mais pour distinguer des fichiers de la console, cela fonctionnera.
@Tobiasbrandt Eh bien, c'est certainement meilleur que toutes les autres solutions "portables". Et sans accès au niveau système FD, je ne pense pas qu'il existe une solution portable. Je suis habitué à programmer au niveau du système, donc j'utiliserais le ISATTY code> /
_ISATTY code> Solution que j'ai proposé dans ma réponse, mais c'est tout aussi bon: il va échouer parfois, mais le mien, tout comme dans différents cas.
Bien sûr, le vrai problème est quelque chose comme myProg | OutilsProg code>. Que devrait-il sortir ici (puisque si la sortie se termine dans la fenêtre du terminal, dans un fichier ou est perdue quelque part dans
quelque autre type code> est inconnu). Ma solution utilisant
isatty code> ne dirait pas un terminal, votre solution dirait que non un fichier; Si votre fonction était précise, elle retournerait
peut-être code>, mais c ++ ne prend pas en charge cela :-). (Bien que le retour d'un
faillible
one est un destream code> et l'autre est un
ostream code>. Il suffit de disposer de deux méthodes.
#include <iostream>
#include <string>
#include <fstream>
class A {
std::string s;
public:
A(const std::string& s) : s(s){}
std::string str() const {return s;}
};
ostream & operator << (std::ostream & os, const A & a)
{
return os << "console: " << a.str() << std::endl;
}
ofstream & operator << (std::ofstream & os, const A & a)
{
return os << "file: " << a.str() << std::endl;
}
int main()
{
A a("hello world");
std::cout << a << endl;
}
Je ne peux pas tester la version du fichier pour ce guichet automatique.
Ceci est (ou peut-être) simplement faux. Un ostream code> peut pointer vers un fichier, et un fichier
ofstream code> peut pointer sur un périphérique interactif (et bien sûr,
std :: cout code> pourrait être un
std :: destream code>).
ostream os = fbrieam ("un fichier"); est << a << endl; code> va écrire "console: ..." dans un fichier.
Je sais cout code> est
extern ostream cout code> mais je ne savais jamais que cela pourrait être un
std :: destream code>. Mais la conversion
ostream OS = ofstream ("Certains fichier"); code> est très probable. C'est jusqu'à OP pour déterminer si cette solution correspondrait à ses besoins actuels et futurs.
@TOBIASBRANDT OSTREAM OS = OFStream ("Certains fichier"); code> ne doit pas compiler.
std :: filebuf fb ("Quelque fichier", std :: ios_base :: sortir); STD :: Ostream OS (& FB); Code> sera cependant un exemple parfait du problème que vous essayez d'augmenter. C'est aussi un idiome très très fréquent, car il permet la sortie d'un fichier, si le nom de fichier est donné et la sortie de
std :: cout code> si ce n'est pas le cas.
@andre bien, la norme fait i> dit qu'ils ont le type std :: ostream code>, mais ceci est probablement un exemple de spécification; Historiquement, sur la plupart des implémentations, ils avaient un type de type dérivé de
std :: ostream code>.
Et bien sûr, en utilisant deux fonctions échoue, seuls si l'utilisateur écrit quelque chose comme somestream << "message:" << A; code>.
Ceci fonctionne sur Visual Studio 2012
if (typeid(os) == typeid(ofstream)) //this is line 17
Cela ne fonctionne nulle part, car il ne prend pas en compte la redirection, ni ostream code> qui sont initialisés avec un
FileBuf code>.
Dans ma défense, il
Il n'y a pas de moyen portable. Sous UNIX, vous pouvez faire: sous Windows, le Bien sûr, cela suppose que vous ne faites pas les choses à confondes
dans votre code. Quelque chose comme: p> par exemple, ou: p> ou même: p> Mais il est à peu près aussi proche que possible de l'obtenir sans le isatty code> devient
_isatty code>, et je ne suis pas sûr
que les macros existent (mais je soupçonne qu'ils le font). P>
FD code>
à partir du
filebuf code>. p> p>
Fonction Pour vérifier si un flux de caractères C ++ est connecté à une borne / console / tty.
Idéalement, nous utiliserions le descripteur de fichier sous la forme du tampon de flux du flux de STDIO C ++ (CIN, COUT, CERR ou sabot). Cependant, il n'ya aucun moyen de récupérer le descripteur de fichier sous-porté. Nous utilisons donc le fait que lors du démarrage du programme Les tampons de flux STDIO sont connectés à l'entrée et à la sortie standard du programme. P>
Cette fonction ne fonctionne que dans les conditions suivantes: P>
Les tampons de flux des flux de start-up c ++ stdio ne doivent pas changer. Étant donné que les adresses des tampons de flux des flux STDIO start-up C ++ sont utilisés comme identifiants. Par exemple, en les supprimant, puis affectant un nouveau tampon de flux qui a la même adresse que l'un de ces tampons de flux des flux STDIO STDIO STRAINT-UP C ++. P> LI>
Le STDIO du programme ne doit pas changer après le démarrage du programme. Parce que les statuts TTY des tampons de flux STDIO sont stockés au démarrage du programme. Par exemple, si au démarrage du STD. Out est connecté à un terminal et plus tard, il est redirigé vers un tuyau ou un fichier par quelque chose d'extérieur au programme. [Au lieu de stocker les statuts TTY au démarrage, vous pouvez les récupérer au moment de l'exécution, mais vous devez alors vous assurer que votre programme (et toutes les bibliothèques utilisées) ne modifie pas les descripteurs de fichiers STDIO (0, 1 et 2) . Ramber que les tampons de flux STDIO utilisent probablement les autres descripteurs de fichiers (duplicataires).] P> li> ol>
code: p> Remarque: Je ne l'ai testé que sous Linux. P> P>
La réponse est certainement dépendante du système d'exploitation. Dans les systèmes UNIX et UNIX, vous pouvez, par exemple, utiliser
isatty (2) code> (où
2 code> est la FD correspondant à
starr code>) Pour détecter si
starr code> pointe vers un terminal. Je n'ai aucune idée de ce que l'équivalent Windows serait.
Comme Joe Z a déclaré, il est dépendant du système d'exploitation, Windows est un peu plus dur à cause de l'API accablant IST. Check Ce pour un début.
@Joez: Même si
starr code> pointe sur un terminal, cela ne signifie pas que l'objet de flux dans
opérateur <<< / code> points à la console. Il pourrait également être fichier: vous pouvez également ouvrir n'importe quel flux dans un programme terminal!
@Nawaz: convenu. Vous devez également obtenir le
fd code> associé au
destream code>. Si vous redistribuez le problème comme «Comment distinguer
COUT code> /
CERR code> à partir d'un autre
destream code> S?", Le problème est beaucoup plus simple et moins OS dépendante et peut-être suffisant à cet effet.
@Joez: Cela pourrait ne pas être suffisant car généralement, vous voudrez peut-être détecter une redirection de bash (pour éviter de mettre en place des caractères de contrôle des couleurs dans un fichier, par exemple). Donc, vous devez réellement avoir besoin à la fois de détecter si les points
ostream code> sur
cout code> ou
cerr code> et si
stdout code> ou < Code> stardr code> est un fichier TTY ou un fichier. Et bien sûr, pour ajouter du plaisir, s'il s'agit d'un TTY, vous voudrez peut-être vérifier ses propriétés pour savoir s'il soutient réellement les couleurs ...
@Matthieum.: Je veux dire "suffisant aux fins de la personne qui demande." Le problème général de la détection de la console vs. Le fichier est très spécifique. Mais, le problème réel que la personne demandant est d'essayer de résoudre peut ne pas être ce général. Nous ne saurons pas à moins qu'ils ne nous disent pas. Il peut être suffisant pour leurs besoins, il suffit de détecter si le flux est
cout code> /
cerr code> ou ils voudront peut-être vraiment savoir s'ils sont dirigés vers un TTY.