Cómo redirigir la salida a la pantalla después de abrir (“out.txt”, “a”, stdout)

#include  int main() { printf("This goes to screen\n"); freopen("out.txt", "a", stdout); printf("This goes to out.txt"); freopen("/dev/stdout", "a", stdout); printf("This should go to screen too, but doesn't\n"); return 0; } 

Llamo a freopen para redirigir el stdout a out.txt luego imprimo algo en el archivo, ahora quiero redirigirlo a la pantalla, pero freopen (“/ dev / stdout”, “a”, stdout); no funciona ¿Hay alguna manera de hacerlo utilizando las llamadas al sistema ANSI C o POSIX?

No puedo pensar en una forma de hacer esto de forma multiplataforma, pero en los sistemas GNU / Linux (y tal vez también en otros POSIX) puede freopen ("/dev/tty", "a", stdout) . ¿Es esto lo que estabas tratando de hacer?

Desafortunadamente, no parece haber una buena manera:

http://c-faq.com/stdio/undofreopen.html

La mejor recomendación es no utilizar freopen en esta circunstancia.

En general, no puedes. Has cerrado el archivo, que podría haber sido canalizado o lo que sea. No es reoperable. Es posible que haya guardado el valor de stdout , luego asigne fopen y luego ciérrelo y copie el valor anterior. Ejemplo:

 FILE *o = stdout; stdout=fopen("/tmp/crap.txt","a"); printf("Oh no!\n"); fclose(stdout); stdout = o; 

Mike Weller sugirió a continuación en los comentarios que stdout no siempre puede escribirse. En este caso, algo así podría ayudar:

 int o = dup(fileno(stdout)); freopen("/tmp/crap.txt","a",stdout); printf("Oh no!\n"); dup2(o,fileno(stdout)); close(o); 

Otra edición: si la está utilizando para redirigir el resultado del proceso secundario, como sugiere su comentario en otro lugar, puede redirigirla después de la bifurcación.

Utilice fdopen() y dup() , así como freopen() .

 int old_stdout = dup(1); // Preserve original file descriptor for stdout. FILE *fp1 = freopen("out.txt", "w", stdout); // Open new stdout ...write to stdout... // Use new stdout FILE *fp2 = fdopen(old_stdout, "w"); // Open old stdout as a stream ...Now, how to get stdout to refer to fp2? ...Under glibc, I believe you can use: fclose(stdout); // Equivalent to fclose(fp1); stdout = fp2; // Assign fp2 to stdout // *stdout = *fp2; // Works on Solaris and MacOS X, might work elsewhere. close(old_stdout); // Close the file descriptor so pipes work sanely 

No estoy seguro de si puede hacer la tarea de manera confiable en otro lugar.

Código dudoso que realmente funciona

El siguiente código funcionaba en Solaris 10 y MacOS X 10.6.2, pero no estoy seguro de que sea confiable. La asignación de estructura puede o no funcionar con Linux glibc.

 #include  #include  int main(void) { printf("This goes to screen\n"); int old_stdout = dup(1); // Consider dup(STDOUT_FILENO) or dup(fileno(stdout)) FILE *fp1 = freopen("out.txt", "a", stdout); printf("This goes to out.txt\n"); fclose(stdout); FILE *fp2 = fdopen(old_stdout, "w"); *stdout = *fp2; // Unreliable! printf("This should go to screen too, but doesn't\n"); return 0; } 

No puedes decir que no fuiste advertido, ¡ esto es jugar con fuego!

Si está en un sistema con el sistema de archivos /dev/fd , puede crear el nombre del archivo implicado por el descriptor de archivo devuelto desde dup() con sprintf(buffer, "/dev/fd/%d", old_stdout) y luego usa freopen() con ese nombre. Esto sería mucho más confiable que la asignación utilizada en este código.

Las mejores soluciones hacen que el código use ‘fprintf (fp, …)’ en todas partes, o use una función de cubierta que le permite establecer su propio puntero de archivo predeterminado:

mprintf.c

 #include "mprintf.h" #include  static FILE *default_fp = 0; void set_default_stream(FILE *fp) { default_fp = fp; } int mprintf(const char *fmt, ...) { va_list args; va_start(args, fmt); if (default_fp == 0) default_fp = stdout; int rv = vfprintf(default_fp, fmt, args); va_end(args); return(rv); } 

mprintf.h

 #ifndef MPRINTF_H_INCLUDED #define MPRINTF_H_INCLUDED #include  extern void set_default_stream(FILE *fp); extern int mprintf(const char *fmt, ...); #endif 

Claramente, puede crear un mvprintf () y otras funciones según sea necesario.

Ejemplo de uso de mprintf ()

Luego, en lugar del código original, puede usar:

 #include "mprintf.h" int main() { mprintf("This goes to screen\n"); FILE *fp1 = fopen("out.txt", "w"); set_default_stream(fp1); mprintf("This goes to out.txt\n"); fclose(fp1); set_default_stream(stdout); mprintf("This should go to screen too, but doesn't\n"); return 0; } 

(Advertencia: código no probado – nivel de confianza demasiado alto. Además, todo el código escrito suponiendo que utiliza un comstackdor C99, principalmente porque declaro variables cuando los necesito por primera vez, no al principio de la función).


Precaución:

Tenga en cuenta que si el progtwig original se invoca como ./original_program > file o ./original_program | grep something ./original_program | grep something (con salida redirigida) o se ejecuta desde un trabajo cron , luego abrir /dev/tty no suele ser apropiado como una forma de volver a abrir la salida estándar porque la salida estándar original no era la terminal.

Además, tenga en cuenta que si la redirección de salida estándar se usa antes de bifurcar y ejecutar un progtwig secundario y la salida estándar original se restablece en el elemento primario, entonces la secuencia de operaciones es incorrecta. Debe doblar y luego ajustar la E / S del niño (solo), sin modificar en absoluto la E / S del padre.

En Windows, puede abrir “CONOUT $”.

 freopen("test.txt", "w", stdout); printf("this goes to test.txt"); freopen("CONOUT$", "w", stdout); printf("this goes to the console\n"); 

Probablemente esto no funcione si se redirige a stdout para comenzar.

El siguiente código (SwapIOB) se usa en bancos de pruebas que desean almacenar la stream stdout para compararla con un archivo de resultados esperado.

Fondo: las secuencias de archivos se administran usando una estructura _IOB que se almacena en una matriz de 20 entradas _IOB. Esto incluye la stream de stdout. Los IOB se almacenan en una matriz. Cuando se crea un archivo, el código de la aplicación obtiene una ptr a un elemento en esa matriz. El código de la aplicación pasa esa ptr al sistema operativo para procesar las llamadas de E / S. Por lo tanto, el sistema operativo no contiene ni se basa en sus propios indicadores en el IOB de la aplicación.

Requisito: cuando se ejecuta un banco de pruebas, los mensajes stdout emitidos por una aplicación deben redirigirse a un archivo. Sin embargo, después de que el módulo bajo prueba se haya completado, los mensajes stdout deberían redireccionarse a la consola.

Esta rutina fue probada y actualmente se usa en el sistema Windows XP / Pro.

 void SwapIOB(FILE *A, FILE *B) { FILE temp; // make a copy of IOB A (usually this is "stdout") memcpy(&temp, A, sizeof(struct _iobuf)); // copy IOB B to A's location, now any output // sent to A is redirected thru B's IOB. memcpy(A, B, sizeof(struct _iobuf)); // copy A into B, the swap is complete memcpy(B, &temp, sizeof(struct _iobuf)); } // end SwapIOB; 

El código de la aplicación usa SwapIOB () similar a:

 FILE *fp; fp = fopen("X", "w"); SwapIOB(stdout, fp); printf("text to file X"); SwapIOB(stdout, fp); fclose(fp); printf("text to console works, again!"); 

Encontré esta publicación porque me encontré con el problema de mezclar la salida de printf y wprintf en una secuencia ( stdout ). Después de estudiar este hilo, descubrí que algo simple como el siguiente código funciona muy bien, siempre que no se use fclose () . (Probado en gcc (Gentoo 4.8.3 p1.1, pie-0.5.9) 4.8.3.). El uso de fclose hace que las llamadas posteriores a printf () fallen, solo la impresión sigue haciendo el trabajo correctamente.

 int fDesc; /* file descriptor */ printf("byte-oriented output\n"); /* printf sets the output as byte-oriented */ fDesc = dup(fileno(stdout)); close(stdout); stdout = fdopen(fDesc,"w"); wprintf(L"wchar-oriented output\n"); /* wprintf sets it to wide-character compat. */ fDesc = dup(fileno(stdout)); close(stdout); stdout = fdopen(fDesc,"w"); /* reopen for byte-oriented output */ printf("byte-oriented output\n"); 

Redirigir la salida a otro archivo desde el caparazón o pasar por encima de las tuberías también funciona bien.

 $> a.out > /tmp/out ; cat /tmp/out $> a.out | sed "s/oriented/aligned/" 

Por cierto, freopen también funciona bien. En código C ++ sería:

 cout < < "some cout text here"; stdout=freopen(NULL,"w",stdout); // NULL to reopen same file name! wcout << L" some wchar_t-s after them" stdout=freopen(NULL,"w",stdout); // reset the stdout again cout << " and some couts again." << endl;