2009-02-25 19 views
51

voglio riaprire il stdin e stdout (e forse stderr mentre io sono a it) filehandle, in modo che le future chiamate a printf() o putchar() o puts() andrà in un file, e future chiamate a getc() e tale verrà da un file.Reinstradamento stdin e stdout da C

1) Non desidero perdere definitivamente input/output/errore standard. Potrei volerli riutilizzare più avanti nel programma.

2) Non desidero aprire nuovi filehandle perché questi filehandle devono essere passati attorno a un lotto o globale (shudder).

3) Non desidero utilizzare nessuna open() o fork() o altre funzioni dipendenti dal sistema se non riesco a evitarlo.

Quindi, in pratica, funziona per fare questo:

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

E, se lo fa, come posso ottenere il valore originale di stdin indietro? Devo memorizzarlo in un FILE * e riprenderlo in seguito?

+0

Si noti che 'stdin',' stdout', e 'stderr' sono variabili globali. –

risposta

69

Perché utilizzare freopen()?La specifica C89 ha la risposta in una delle note di chiusura per la sezione on <stdio.h>:

116. L'uso primario della funzione freopen è quello di cambiare il file associato a un flusso testo standard (stderr , stdin, o stdout), in cui tali identificatori non devono essere lvalue modificabili per cui il valore restituito dal fopen può essere assegnata la funzione .

freopen viene comunemente utilizzato in modo improprio, ad es. stdin = freopen("newin", "r", stdin);. Questo non è più portatile di fclose(stdin); stdin = fopen("newin", "r");. Entrambe le espressioni tentano di assegnare a stdin, che non è garantito per essere assegnabile.

Il modo giusto di usare freopen è di omettere l'assegnazione: freopen("newin", "r", stdin);

+9

come ripristinarlo allora? – AbiusX

+3

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

+0

@AbiusX Non sono sicuro di quanto questo sia portatile, ma in ambienti POSIX è possibile farlo in un altro modo, cambiando il significato dell'handle sottostante con 'dup2() ': http://linux.die.net/man/3/fflush. Ciò ti consente di duplicare l'handle STDOUT prima di sostituirlo, quindi puoi ricopiarlo. Ricordati di 'fflush()'. C'è un esempio di ciò che viene utilizzato per andare qui: http://stackoverflow.com/questions/9405985/linux-3-0-executing-child-process-with-piped-stdin-stdout –

14

Credo che tu stia cercando qualcosa di simile freopen()

+0

C'è qualche differenza tra stdin = freopen ("newin", "r", stdin); e fclose (stdin); stdin = fopen ("newin", "r"); o no? –

+0

fopen apre un oggetto file mentre freopen punta il flusso di dati all'oggetto file. Dalla pagina "Questa funzione è particolarmente utile per reindirizzare flussi predefiniti come stdin, stdout e stderr su file specifici" –

+1

C'è un modo per riaprire stdin/stdout ai loro valori originali diversi da stdin = freopen ("/ dev/tty", "r"); o qualcosa? –

8

La funzione OS dup2() dovrebbe fornire ciò che è necessario (se non i riferimenti a esattamente ciò che serve).

In particolare, è possibile dup2() il descrittore di file stdin in un altro descrittore di file, eseguire altre operazioni con stdin e quindi copiarlo quando lo si desidera.

La funzione dup() duplica un descrittore di file aperto. In particolare, fornisce un'interfaccia alternativa al servizio fornito dalla funzione fcntl() utilizzando il valore del comando costante F_DUPFD, con 0 per il suo terzo argomento. Il descrittore di file duplicato condivide tutti i blocchi con l'originale.

In caso di successo, dup() restituisce un nuovo descrittore di file che ha il seguente in comune con l'originale:

  • Stesso file aperti (o tubo)
  • stesso puntatore del file (entrambi i descrittori di file condividono un puntatore al file)
  • modalità di accesso Same (lettura, scrittura o lettura/scrittura)
+0

La domanda dice esplicitamente di non utilizzare le funzioni dipendenti dal sistema. – unwind

+0

E la domanda dice esplicitamente di limitare il numero di stream/descrittori di file aperti –

3

freopen risolve la parte facile. Mantenere il vecchio stdin in giro non è difficile se non hai letto nulla e se sei disposto a utilizzare le chiamate di sistema POSIX come dup o dup2. Se hai iniziato a leggere da esso, tutte le scommesse sono disattivate.

Forse puoi dirci il contesto in cui si verifica questo problema?

Vorrei incoraggiarvi ad attenervi alle situazioni in cui siete disposti ad abbandonare il vecchio stdin e stdout e quindi utilizzare freopen.

+0

Nel contesto, penso che potrei farla franca abbandonando il vecchio stdin/stdout se davvero dovessi farlo. Sto cercando di aggiungere al mio programma un'opzione per il reindirizzamento di stdin e stdout, per le persone che eseguono il programma e non conoscono molto bene la shell. Solo per l'inferno. –

+1

I miei studenti hanno sicuramente problemi con il reindirizzamento I/O, quindi il tuo obiettivo sembra buono. Forse staresti meglio con le opzioni della riga di comando -i e -o per nominare i file di input e di output? –

+0

Questo è il mio piano più o meno (-i e -o sono già stati presi, ma questa è l'interfaccia generale), avevo solo bisogno di un modo per implementarlo (senza dover cambiare tutti i miei printf() s per fprintf() s e passare circa due filehandle in ogni direzione). Inoltre, una bandiera per il reinstradamento dello stderr sarebbe bella. –

8
freopen("/my/newstdin", "r", stdin); 
freopen("/my/newstdout", "w", stdout); 
freopen("/my/newstderr", "w", stderr); 

... do your stuff 

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

Questa picchi la puntina sul mio giro-peg-piazza-hole-o-meter, che cosa stai cercando di realizzare?

Edit:

Ricordate che stdin, stdout e stderr sono descrittori di file 0, 1 e 2 per ogni processo di nuova creazione. freopen() dovrebbe mantenere lo stesso valore di fd, basta assegnargli nuovi stream.

Quindi, un buon modo per garantire che questo sta effettivamente facendo quello che vuoi da fare sarebbe:

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)); 

Credo che questo sia il comportamento previsto freopen(), come si può vedere, è Stai ancora usando solo tre descrittori di file (e flussi associati).

Ciò sostituirà qualsiasi reindirizzamento della shell, in quanto non ci sarebbe nulla da reindirizzare per la shell. Tuttavia, probabilmente sta andando a rompere i tubi. Potresti voler impostare un gestore per SIGPIPE, nel caso in cui il tuo programma si trovi sul lato di blocco di una pipe (non FIFO, pipe).

Quindi, ./your_program --stdout /tmp/stdout.txt --stderr /tmp/stderr.txt deve essere facilmente realizzato con freopen() e mantenendo gli stessi descrittori di file effettivi. Quello che non capisco è il motivo per cui dovresti reinserirli una volta modificati? Sicuramente, se qualcuno passasse una delle due opzioni, vorrebbero che persistesse fino alla fine del programma?

+0

Sto cercando di aggiungere un modo per il mio programma per reindirizzare il proprio input e output standard, per le persone che non si sentono a proprio agio con il reindirizzamento della shell. –

+0

Sì, freopen() sarà tuo amico per questo. –

+0

Questo non funziona come lo descrivi. Ho usato il seguente codice: printf ("Questo dovrebbe essere visibile sullo schermo! \ N"); freopen ("testop.txt", "w", stdout); printf ("Questo dovrebbe andare a testop!\ n "); fflush (stdout); fclose (stdout); freopen ("/dev/stdout "," w ", stdout); printf (" E questo dovrebbe andare di nuovo sullo schermo! \ n " – VectorVictor

9

Questa è una versione modificata del metodo di Tim Post; Ho usato/dev/tty invece di/dev/stdout. Non so il motivo per cui non funziona con stdout (che è un link a/proc/self/fd/1):

freopen("log.txt","w",stdout); 
... 
... 
freopen("/dev/tty","w",stdout); 

Utilizzando/dev/tty l'output viene reindirizzato al terminale da dove è stata lanciata l'app.

Spero che questa informazione sia utile.

3

E nel frattempo, c'è una libreria di codice sorgente C che farà tutto questo per te, reindirizzando stdout o stderr. Ma la parte interessante è che ti consente di assegnare tutte le funzioni di callback che vuoi agli stream intercettati, consentendo quindi di inviare facilmente un singolo messaggio a più destinazioni, un DB, un file di testo, ecc.

Acceso Per di più, rende banale la creazione di nuovi flussi che guardano e si comportano allo stesso modo di stdout e stderr, dove è possibile reindirizzare questi nuovi flussi anche in più posizioni.

Cerca libreria U-Streams su * oogle.

0

questo è il moste Disponibile handly e modo utile

freopen("dir","r",stdin); 
Problemi correlati