So leiten Sie die Ausgabe nach freopen(“out.txt”, “a”, stdout) wieder auf den Bildschirm um
Lesezeit: 8 Minuten
#include <stdio.h>
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;
}
Ich rufe freopen an, um die umzuleiten stdout in out.txt drucke ich dann etwas auf die Datei, jetzt möchte ich es wieder auf den Bildschirm umleiten, aber freopen(“/dev/stdout”, “a”, stdout); funktioniert nicht. Gibt es eine Möglichkeit, dies mit ANSI C- oder POSIX-Systemaufrufen zu tun?
Ich kann mir keine Möglichkeit vorstellen, dies plattformübergreifend zu tun, aber auf GNU/Linux-Systemen (und vielleicht auch anderen POSIX-kompatiblen) ist dies möglich freopen ("/dev/tty", "a", stdout). Ist es das, was Sie versucht haben?
Dies wird die Dinge im Falle einer Umleitung oder Weiterleitung an einen anderen Prozess beschädigen.
– Michael Krelin – Hacker
15. Dezember 2009 um 19:07 Uhr
Nur der letzte Prozess, den ich aufforke (), muss auf den Bildschirm umgeleitet werden. Das funktioniert also in meinem Fall.
– Hoffmann
15. Dezember 2009 um 20:30 Uhr
Hoffman, natürlich kann es für Ihren speziellen Fall gut genug sein, also schreibe ich diese Kommentare für diejenigen, die die Frage finden und sich vielleicht um den Fall kümmern, wenn das Ganze umgeleitet wird oder überhaupt kein tty hat.
– Michael Krelin – Hacker
15. Dezember 2009 um 23:01 Uhr
Ich stimme zu, Hacker. Ich mag die Lösung von Jonathan Leffler unten, in der wir einen Wrapper für printf und einen Standardstream haben. Eine sehr schöne Lösung und auch plattformübergreifend (soweit ich das beurteilen kann).
Die beste Empfehlung ist, freopen unter diesen Umständen nicht zu verwenden.
Michael Krelin – Hacker
Generell kann man das nicht. Sie haben die Datei geschlossen, die eine Pfeife oder was auch immer sein könnte. Es kann nicht wieder geöffnet werden. Vielleicht hast du gespart stdout Wert, weisen Sie ihm dann etwas fopen zu und schließen Sie es dann und kopieren Sie den alten Wert zurück. Beispiel:
Mike Weller schlug unten in Kommentaren vor, dass stdout möglicherweise nicht immer beschreibbar ist. In diesem Fall könnte so etwas helfen:
int o = dup(fileno(stdout));
freopen("/tmp/crap.txt","a",stdout);
printf("Oh no!\n");
dup2(o,fileno(stdout));
close(o);
Eine weitere Bearbeitung: Wenn Sie damit die Ausgabe des untergeordneten Prozesses umleiten, wie Ihr Kommentar an anderer Stelle vorschlägt, können Sie ihn nach der Verzweigung umleiten.
Außer dass stdio unter einigen Implementierungen wahrscheinlich nicht zuverlässig beschreibbar ist.
– Mike Weller
15. Dezember 2009 um 17:50 Uhr
Mike Weller, könnte sein. Ich habe versucht, eine alternative Lösung anzubieten.
– Michael Krelin – Hacker
15. Dezember 2009 um 19:06 Uhr
Jonathan Leffler
Verwenden fdopen() und dup() ebenso gut wie 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
Ich bin mir nicht sicher, ob Sie die Aufgabe woanders zuverlässig erledigen können.
Dubioser Code, der tatsächlich funktioniert
Der folgende Code funktionierte unter Solaris 10 und MacOS X 10.6.2 – aber ich bin nicht sicher, ob er zuverlässig ist. Die Strukturzuweisung kann mit Linux glibc funktionieren oder nicht.
#include <stdio.h>
#include <unistd.h>
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;
}
Du kannst nicht sagen, dass du nicht gewarnt wurdest – das ist ein Spiel mit dem Feuer!
Wenn Sie sich auf einem System mit dem befinden /dev/fd Dateisystem, könnten Sie den Namen der Datei erstellen, der durch den zurückgegebenen Dateideskriptor impliziert wird dup() mit sprintf(buffer, "/dev/fd/%d", old_stdout) und dann verwenden freopen() mit diesem Namen. Dies wäre viel zuverlässiger als die in diesem Code verwendete Zuweisung.
Die besseren Lösungen lassen den Code entweder überall ‘fprintf(fp, …)’ verwenden oder verwenden eine Cover-Funktion, mit der Sie Ihren eigenen Standarddateizeiger festlegen können:
Natürlich können Sie nach Bedarf ein mvprintf() und andere Funktionen erstellen.
Beispielverwendung von mprintf()
Dann können Sie anstelle des ursprünglichen Codes Folgendes verwenden:
#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;
}
(Warnung: ungetesteter Code – Konfidenzniveau zu hoch. Außerdem wird der gesamte Code unter der Annahme geschrieben, dass Sie einen C99-Compiler verwenden, hauptsächlich weil ich Variablen deklariere, wenn ich sie zum ersten Mal benötige, nicht am Anfang der Funktion.)
Vorsicht:
Beachten Sie, dass wenn das ursprüngliche Programm aufgerufen wird als ./original_program > file oder ./original_program | grep something (mit umgeleiteter Ausgabe) oder wird von a ausgeführt cron Job, dann Eröffnung /dev/tty ist normalerweise nicht geeignet, um die Standardausgabe erneut zu öffnen, da die ursprüngliche Standardausgabe nicht das Terminal war.
Beachten Sie auch, dass die Reihenfolge der Operationen falsch ist, wenn die Umleitung der Standardausgabe vor dem Forken und Ausführen eines untergeordneten Programms verwendet wird und die ursprüngliche Standardausgabe im übergeordneten Programm wiederhergestellt wird. Sie sollten (nur) die E / A des untergeordneten Elements forken und dann anpassen, ohne die E / A des übergeordneten Elements überhaupt zu ändern.
Unter Windows können Sie “CONOUT$” öffnen.
freopen("test.txt", "w", stdout);
printf("this goes to test.txt");
freopen("CONOUT$", "w", stdout);
printf("this goes to the console\n");
Dies funktioniert wahrscheinlich nicht, wenn stdout zu Beginn umgeleitet wird.
Ihre Lösung erlaubte mir nicht, stderr wiederherzustellen. Dieser Artikel über _dup funktioniert bei mir.
– Brandlingo
22. Oktober 2014 um 15:04 Uhr
@cegprakash Hast du CONIN$ für stdin geöffnet?
– Benutzer253751
29. März 2016 um 19:38 Uhr
Ich verwende nur freopen (“test1.txt”, “r”, stdin); und nach einiger Zeit möchte ich freopen (“test2.txt”, “r”, stdin) ausführen, aber stdin zeigt immer noch auf die erste Datei.
– cegprakash
1. April 2016 um 10:05 Uhr
JackCColeman
Der folgende Code (SwapIOB) wird in Testbenches verwendet, die den stdout-Stream zum Vergleich mit einer erwarteten Ergebnisdatei speichern möchten.
Hintergrund: Dateistreams werden mit einer _IOB-Struktur verwaltet, die in einem Array von 20 _IOB-Einträgen gespeichert wird. Dies schließt den stdout-Stream ein. Die IOBs werden in einem Array gespeichert. Wenn eine Datei erstellt wird, erhält der Anwendungscode einen PTR zu einem Element in diesem Array. Der Anwendungscode übergibt diesen ptr dann an das Betriebssystem zur Verarbeitung von E/A-Aufrufen. Somit enthält oder stützt sich das OS selbst NICHT auf seine eigenen Zeiger auf den IOB der Anwendung.
Anforderung: Beim Ausführen einer Testbench sollen die von einer Anwendung ausgegebenen stdout-Meldungen in eine Datei umgeleitet werden. Nachdem das zu testende Modul jedoch abgeschlossen ist, sollten stdout-Meldungen an die Konsole umgeleitet werden.
Diese Routine wurde getestet und wird derzeit auf Windows XP/Pro-Systemen verwendet.
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;
Anwendungscode verwendet SwapIOB() ähnlich wie:
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!");
Ihre Lösung erlaubte mir nicht, stderr wiederherzustellen. Dieser Artikel über _dup funktioniert bei mir.
– Brandlingo
22. Oktober 2014 um 15:04 Uhr
@cegprakash Hast du CONIN$ für stdin geöffnet?
– Benutzer253751
29. März 2016 um 19:38 Uhr
Ich verwende nur freopen (“test1.txt”, “r”, stdin); und nach einiger Zeit möchte ich freopen (“test2.txt”, “r”, stdin) ausführen, aber stdin zeigt immer noch auf die erste Datei.
– cegprakash
1. April 2016 um 10:05 Uhr
13815400cookie-checkSo leiten Sie die Ausgabe nach freopen(“out.txt”, “a”, stdout) wieder auf den Bildschirm umyes