web-dev-qa-db-fra.com

Reroutage de stdin et stdout à partir de C

Je veux rouvrir les descripteurs de fichiers stdin et stdout (et peut-être stderr pendant que j'y suis), afin que les futurs appels à printf() ou putchar() ou puts() ira dans un fichier, et les futurs appels à getc() et ceux-ci proviendront d'un fichier.

1) Je ne veux pas perdre définitivement les entrées/sorties/erreurs standard. Je peux vouloir les réutiliser plus tard dans le programme.

2) Je ne veux pas ouvrir de nouveaux descripteurs de fichiers car ces descripteurs de fichiers devraient être soit beaucoup circulés soit globaux (frémissement).

3) Je ne veux pas utiliser de open() ou fork() ou d'autres fonctions dépendant du système si je ne peux pas m'en empêcher.

Donc, en gros, ça marche:

stdin = fopen("newin", "r");

Et si c'est le cas, comment récupérer la valeur d'origine de stdin? Dois-je le stocker dans un FILE * et le récupérer plus tard?

60
Chris Lutz

Je pense que vous cherchez quelque chose comme freopen()

15
John T

La fonction os dup2 () devrait fournir ce dont vous avez besoin (sinon des références à exactement ce dont vous avez besoin).

Plus spécifiquement, vous pouvez dup2 () le descripteur de fichier stdin vers un autre descripteur de fichier, faire d'autres choses avec stdin, puis le recopier quand vous le souhaitez.

La fonction dup () duplique un descripteur de fichier ouvert. Plus précisément, il fournit une interface alternative au service fourni par la fonction fcntl () en utilisant la valeur de commande constante F_DUPFD, avec 0 pour son troisième argument. Le descripteur de fichier dupliqué partage tous les verrous avec l'original.

En cas de succès, dup () renvoie un nouveau descripteur de fichier qui a en commun ce qui suit avec l'original:

  • Même fichier ouvert (ou pipe)
  • Même pointeur de fichier (les deux descripteurs de fichiers partagent un pointeur de fichier)
  • Même mode d'accès (lecture, écriture ou lecture/écriture)
9
gahooa
freopen("/my/newstdin", "r", stdin);
freopen("/my/newstdout", "w", stdout);
freopen("/my/newstderr", "w", stderr);

... do your stuff

freopen("/dev/stdin", "r", stdin);
...
...

Cela pointe l'aiguille sur mon rond-cheville-carré-o-mètre, qu'essayez-vous d'accomplir?

Modifier:

N'oubliez pas que stdin, stdout et stderr sont des descripteurs de fichier 0, 1 et 2 pour chaque processus nouvellement créé. freopen () devrait conserver les mêmes fd, il suffit de leur assigner de nouveaux flux.

Donc, un bon moyen de s'assurer que cela fait réellement ce que vous voulez qu'il soit:

printf("Stdout is descriptor %d\n", fileno(stdout));
freopen("/tmp/newstdout", "w", stdout);
printf("Stdout is now /tmp/newstdout and hopefully still fd %d\n",
   fileno(stdout));
freopen("/dev/stdout", "w", stdout);
printf("Now we put it back, hopefully its still fd %d\n",
   fileno(stdout));

Je crois que c'est le comportement attendu de freopen (), comme vous pouvez le voir, vous n'utilisez toujours que trois descripteurs de fichiers (et les flux associés).

Cela remplacerait toute redirection Shell, car il n'y aurait rien à rediriger Shell. Cependant, cela va probablement casser des tuyaux. Vous voudrez peut-être être sûr de configurer un gestionnaire pour SIGPIPE, au cas où votre programme se trouverait à l'extrémité bloquante d'un canal (pas FIFO, canal).

Donc, ./votre_programme --stdout /tmp/stdout.txt --stderr /tmp/stderr.txt devrait être facilement accompli avec freopen () et en gardant les mêmes descripteurs de fichiers réels. Ce que je ne comprends pas, c'est pourquoi vous auriez besoin de les remettre une fois les changer? Sûrement, si quelqu'un a réussi l'une ou l'autre option, il voudrait qu'elle persiste jusqu'à la fin du programme?

9
Tim Post

Et en attendant, il y a une bibliothèque de code source C qui fera tout cela pour vous, redirigeant stdout ou stderr. Mais la partie intéressante est qu'il vous permet d'affecter autant de fonctions de rappel que vous le souhaitez aux flux interceptés, ce qui vous permet ensuite d'envoyer très facilement un seul message vers plusieurs destinations, une base de données, un fichier texte, etc.

En plus de cela, il est trivial de créer de nouveaux flux qui ressemblent et se comportent de la même manière que stdout et stderr, où vous pouvez également rediriger ces nouveaux flux vers plusieurs emplacements.

recherchez la bibliothèque U-Streams C sur * oogle.

3
john

freopen résout la partie facile. Garder l'ancien stdin n'est pas difficile si vous n'avez rien lu et si vous êtes prêt à utiliser des appels système POSIX comme dup ou dup2. Si vous commencez à lire, tous les paris sont désactivés.

Peut-être pouvez-vous nous dire dans quel contexte ce problème se produit?

Je vous encourage à vous en tenir aux situations où vous êtes prêt à abandonner les anciens stdin et stdout et pouvez donc utiliser freopen.

3
Norman Ramsey

c'est le moyen le plus pratique et le plus utile disponible

freopen("dir","r",stdin);
0
afr0ck