HOWTO · C
Usa il reindirizzamento dei file in C
In questo articolo viene illustrato come utilizzare il reindirizzamento dei file in C
In questa pagina
Per reindirizzare dalla riga di comando l’input o l’output di un programma C, usa gli operatori della shell <, > e >>. La shell collega i flussi standard del programma ai file; in alternativa, il codice C può aprire un file specifico con fopen oppure modificare un flusso standard con freopen. Sono modi correlati di gestire i dati, ma si tratta di operazioni diverse.
Capire la redirezione dei file in C
Un processo C parte con tre flussi standard: stdin per l’input, stdout per l’output normale e stderr per i messaggi diagnostici. Di norma, la shell li collega al terminale. La redirezione modifica questi collegamenti quando avvia il programma, così il programma può continuare a chiamare fgets, printf o fprintf(stderr, ...) senza sapere se un flusso è diretto a un terminale o a un file.
Al contrario, fopen restituisce un FILE * separato, che il codice legge o scrive direttamente. Usalo quando il programma deve scegliere tra più file, gestirne diversi contemporaneamente o controllarne il ciclo di vita. Usa la redirezione della shell quando vuoi che sia chi avvia il programma a scegliere la destinazione dell’input o dell’output.
Reindirizzare l’output del programma con > e »
Questo breve programma scrive una riga su stdout:
Esegui questo esempio:
Il codice e le etichette o gli output visibili in questa sezione restano in inglese.
#include <stdio.h>
int main(void) {
puts("Report complete");
return 0;
}
La riga del programma viene inviata a stdout; questo esempio non include una trascrizione dell’esecuzione. Dopo aver compilato il programma con il nome report, eseguilo con ./report > report.txt per creare o sovrascrivere report.txt. Per aggiungere il contenuto alla fine del file, usa ./report >> report.txt. L’operatore > tronca una destinazione esistente prima che il programma venga avviato, mentre >> scrive in fondo. La sintassi della shell e i comandi di compilazione disponibili variano a seconda della piattaforma.
La shell si occupa di aprire la destinazione reindirizzata. Se non riesce ad aprirla, segnala il problema e, di norma, non avvia il programma. Il programma non può rilevare questo caso come un errore di fopen, perché non è stato lui ad aprire la destinazione. Per salvare i messaggi diagnostici in un file separato, usa ./report > report.txt 2> errors.txt; 2> reindirizza il descrittore di file convenzionalmente usato per stderr.
Reindirizzare l’input del programma con <
Leggi da stdin quando vuoi lasciare a chi avvia il programma la scelta della sorgente di input. Questo programma legge righe finché il file reindirizzato non raggiunge la fine:
Il codice e le etichette o gli output visibili in questa sezione restano in inglese.
#include <stdio.h>
int main(void) {
char line[128];
while (fgets(line, sizeof line, stdin) != NULL) {
if (fputs(line, stdout) == EOF) {
perror("writing stdout");
return 1;
}
}
if (ferror(stdin)) {
perror("reading stdin");
return 1;
}
return 0;
}
Compilalo con il nome copy-input, quindi esegui ./copy-input < input.txt. fgets legge al massimo un carattere in meno rispetto alla capacità del buffer, aggiunge il carattere nullo terminatore e conserva il carattere di nuova riga se ne legge uno. Di conseguenza, una riga lunga può essere restituita in più parti. Dopo il ciclo, controlla ferror per distinguere un errore di lettura dalla normale fine del file. Il comportamento dell’esempio deriva dalle operazioni sui flussi C mostrate; qui non è fornito alcun output osservato.
Reindirizzare i flussi standard all’interno di un programma C
Quando è il programma stesso a dover scegliere una destinazione, freopen può riaprire un flusso standard. Accetta un percorso, una modalità come "w" o "a" e il flusso da riaprire. Per esempio, freopen("run.log", "a", stdout) invia l’output standard successivo in fondo a run.log. Prima di scrivere, controlla il valore restituito: se la riapertura non riesce, la funzione restituisce NULL. Questa operazione modifica il flusso del processo; fopen, invece, fornisce un altro flusso e lascia stdout invariato.
Usa questa soluzione quando la redirezione fa parte del comportamento del programma. Se la destinazione deve essere scelta da chi lo avvia, lascia stdout invariato e usa > o >>. freopen fa parte dello standard C, ma i dettagli sulla riapertura di un flusso dopo un errore possono dipendere dall’implementazione. Gestisci il risultato NULL e non proseguire come se la redirezione fosse riuscita.
Gestire gli errori e scegliere l’approccio giusto
Controlla ogni operazione che può fallire. Verifica fopen e freopen prima di usare il flusso restituito; controlla che le funzioni di output, come fprintf o fputs, non segnalino un errore; e controlla fclose se è importante sapere che l’output bufferizzato sia arrivato al file. Nei cicli di lettura, se fgets restituisce NULL, potrebbe trattarsi della fine del file oppure di un errore di lettura: controlla ferror per distinguerli. perror può mostrare un messaggio del sistema operativo relativo a un errore associato al valore corrente di errno.
Non dimensionare un buffer per una riga usando la lunghezza in byte dichiarata dal file: l’input potrebbe provenire da una pipe o da un terminale e una riga potrebbe essere più lunga del buffer scelto. Un buffer di dimensione fissa, usato con chiamate ripetute a fgets, è adatto quando è accettabile elaborare l’input a blocchi. Per leggere una riga logica di lunghezza arbitraria, amplia il buffer man mano che arrivano i blocchi e controlla i limiti di allocazione e dei calcoli, oppure usa una funzione di lettura specifica della piattaforma, dichiarandone i limiti di portabilità.
Scegli la redirezione della shell per collegare i flussi standard di un’esecuzione, fopen per gestire in C un file aggiuntivo e freopen quando il programma deve sostituire direttamente un flusso standard. Quando l’output normale è reindirizzato, lascia i messaggi diagnostici su stderr; controlla gli errori nel livello che esegue l’operazione.