Reencaminando stdin y stdout desde C
redirect stdio (8)
¿Por qué usar freopen()
? La especificación C89 tiene la respuesta en una de las notas al final para la sección en <stdio.h>
:
116. El uso principal de la función
freopen
es cambiar el archivo asociado a una secuencia de texto estándar (stderr
,stdin
ostdout
), ya que esos identificadores no necesitan ser valores modificables a los que se les pueda asignar el valor devuelto por la funciónfopen
.
freopen
es comúnmente mal utilizado, por ejemplo, stdin = freopen("newin", "r", stdin);
. Esto no es más portátil que fclose(stdin); stdin = fopen("newin", "r");
fclose(stdin); stdin = fopen("newin", "r");
. Ambas expresiones intentan asignar a stdin
, que no se garantiza que sea asignable.
La forma correcta de usar freopen
es omitir la asignación: freopen("newin", "r", stdin);
Quiero volver a abrir los manejadores de archivos stdin
y stdout
(y quizás stderr
mientras estoy en ello), de modo que futuras llamadas a printf()
o putchar()
o puts()
irán a un archivo, y futuras llamadas a getc()
y tal procederá de un archivo.
1) No quiero perder de forma permanente la entrada / salida / error estándar. Es posible que desee reutilizarlos más adelante en el programa.
2) No quiero abrir nuevas manetas de archivo porque estas manetas de archivo tendrían que pasar mucho o global (temblor).
3) No quiero usar ninguna función open()
o fork()
u otras funciones dependientes del sistema si no puedo evitarlo.
Entonces, básicamente, ¿funciona para hacer esto?
stdin = fopen("newin", "r");
Y, si lo hace, ¿cómo puedo recuperar el valor original de stdin
? ¿Tengo que guardarlo en un FILE *
y recuperarlo más tarde?
Creo que estás buscando algo como freopen()
Esta es una versión modificada del método de Tim Post; Usé / dev / tty en lugar de / dev / stdout. No sé por qué no funciona con stdout (que es un enlace a / proc / self / fd / 1):
freopen("log.txt","w",stdout);
...
...
freopen("/dev/tty","w",stdout);
Al usar / dev / tty, la salida se redirige al terminal desde donde se lanzó la aplicación.
Espero que esta información sea útil.
Y mientras tanto, hay una biblioteca de código fuente C que hará todo esto por usted, redirigiendo stdout o stderr. Pero lo bueno es que le permite asignar tantas funciones de devolución de llamada como desee a las transmisiones interceptadas, lo que le permite enviar fácilmente un solo mensaje a múltiples destinos, una base de datos, un archivo de texto, etc.
Además de eso, es trivial crear nuevas secuencias que se vean y se comporten de la misma manera que stdout y stderr, donde también se pueden redirigir estas nuevas transmisiones a varias ubicaciones.
busque la biblioteca U-Streams C en * oogle.
este es el mejor camino disponible y útil
freopen("dir","r",stdin);
freopen
resuelve la parte fácil. Mantener el estilo antiguo no es difícil si no ha leído nada y si está dispuesto a usar llamadas al sistema POSIX como dup
o dup2
. Si comenzó a leer, todas las apuestas están desactivadas.
¿Tal vez nos puede decir el contexto en el que ocurre este problema?
Le recomiendo que se adhiera a las situaciones en las que está dispuesto a abandonar el viejo stdin
y stdout
y, por lo tanto, puede usar freopen
.
La función os dup2() debe proporcionar lo que necesita (si no hace referencia exactamente a lo que necesita).
Más específicamente, puede duplicar (2) el descriptor de archivo stdin a otro descriptor de archivo, hacer otras cosas con stdin y luego copiarlo cuando lo desee.
La función dup () duplica un descriptor de archivo abierto. Específicamente, proporciona una interfaz alternativa al servicio proporcionado por la función fcntl () utilizando el valor de comando constante F_DUPFD, con 0 para su tercer argumento. El descriptor de archivo duplicado comparte cualquier bloqueo con el original.
En caso de éxito, dup () devuelve un nuevo descriptor de archivo que tiene lo siguiente en común con el original:
- El mismo archivo abierto (o tubería)
- El mismo puntero de archivo (ambos descriptores de archivo comparten un puntero de archivo)
- Mismo modo de acceso (lectura, escritura o lectura / escritura)
freopen("/my/newstdin", "r", stdin);
freopen("/my/newstdout", "w", stdout);
freopen("/my/newstderr", "w", stderr);
... do your stuff
freopen("/dev/stdin", "r", stdin);
...
...
Esto hace un pico en la aguja de mi tapón redondo, agujero cuadrado y metro, ¿qué intentas lograr?
Editar:
Recuerde que stdin, stdout y stderr son descriptores de archivos 0, 1 y 2 para cada proceso recién creado. freopen () debería mantener los mismos fd, solo asignarles nuevas transmisiones.
Entonces, una buena manera de asegurarse de que esto realmente está haciendo lo que quiere que haga sería:
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));
Creo que este es el comportamiento esperado de freopen (), como puede ver, solo está utilizando tres descriptores de archivos (y flujos asociados).
Esto anularía cualquier redirección de shell, ya que no habría nada para que el shell redireccionara. Sin embargo, es probable que rompa las tuberías. Es posible que desee asegurarse de configurar un controlador para SIGPIPE, en caso de que su programa se encuentre en el extremo de bloqueo de una tubería (no FIFO, tubería).
Por lo tanto, ./your_program --stdout /tmp/stdout.txt --stderr /tmp/stderr.txt se debe completar fácilmente con freopen () y manteniendo los mismos descriptores de archivo reales. Lo que no entiendo es por qué tendrías que volver a ponerlos una vez que los cambies? Seguramente, si alguien aprobó cualquiera de las opciones, querrían que persistiera hasta que el programa terminara?