2013-07-30 23 views
5
gcc (GCC) 4.7.2 
c89 

E 'possibile verificare se un file è già stato chiuso?Controllare se un file che è stato aperto con fopen è stato chiuso

Ho aperto un file utilizzando fopen() e chiuso utilizzando fclose(fd).

Questo file viene aperto e chiuso durante l'esecuzione del programma. Tuttavia, l'utente può terminare il programma facendo un ctrl-c.

Quando vado alla mia routine di pulizia, non so se il file è in uno stato aperto o chiuso. Quindi, se provo a fare uno fclose(fd) due volte, impilerà il dump.

Alcune idee sono stato gettando intorno:

  1. Aggiungi uno stato per il file da sia aperto o chiuso, e quindi verificare che lo stato, significa più lavoro per un lavoro così semplice.
  2. Non eseguire alcuna operazione in quanto il sistema operativo verrà automaticamente ripulito al termine del programma.
  3. C'è la funzione di accesso, ma che controllerà solo la modalità.

Molte grazie in anticipo,

+0

L'aggiunta di uno stato (la prima opzione) aggiungerebbe una condizione di competizione a meno che non si maschera il segnale Ctrl + C mentre lo stato è sincronizzato con il file. – Inspired

+4

perché non è possibile impostare 'fd' _ (nome strano, btw) _ su' NULL' dopo la chiusura? – VoidPointer

+0

È più correlato alla libc (spesso Glibc, ma potrebbe essere [musl-libc] (http://musl-libc.org/) ecc.) Rispetto al compilatore. –

risposta

4

AFAIK, glibc non fornisce un metodo per convalidare una variabile FILE*.

Mantenere una sorta di stato o semplicemente impostando fd a NULL opere, ma bisogna stare attenti a non entrare nella vostra routine di pulizia solo dopo aver chiuso il file, ma prima di resettare fd. Mentre Ctrl + C invia un segnale (SIGINT) ad un programma, puoi semplicemente bloccare il segnale mentre il file viene chiuso e viene ripristinato fd. Così, il vostro fclose nel programma principale dovrebbe essere simile:

// 1. Block SIGINT 
sigset_t old_mask, to_block; 
sigemptyset(&to_block); 
sigaddset(&to_block, SIGINT); 
sigprocmask(SIG_BLOCK, &to_block, &old_mask); 

// 2. Close the file and reset fd 
fclose(fd); 
fd = NULL; 

// 3. Restore signal handling 
sigprocmask(SIG_SETMASK, &old_mask, NULL); 

E nella vostra routine di pulizia si dovrebbe solo controllare fd:

if (fd != NULL) fclose(fd); 

Se il programma è multithreaded, è consigliabile utilizzare pthread_sigmask invece .

Nel tuo caso, la semplice chiamata di fcloseall() nella routine di pulizia sarebbe molto più semplice.

Per quanto riguarda la seconda opzione implicita nella tua domanda, sul non fare nulla - beh, il sistema operativo ripulirà tutto per il tuo programma. Quindi l'unico inconveniente è che se ci sono stati aperti flussi di scrittura, alcuni dati potrebbero non essere scritti su disco. Ma forse nel caso di Ctrl + C è ok.

+0

Che cosa è * AFAIK * btw? –

+4

Per quanto ne so, AFAIK è l'abbreviazione di "Per quanto ne so" :) – Inspired

+1

Grazie, non sapevo –

1

Può essere aiuti voi, solo alcuni suggerimenti:

È possibile controllare file aperto dal processo utilizzando il processo id.

  1. pid_t getpid(void);, restituire l'ID di processo del processo di chiamata.
  2. Quindi passare questo PID al comando pfiles.

Secondo:

È possibile chiamare int fcloseall (void); prima di programma termina.

Questa funzione comporta flussi tutte aperte del processo da chiudere e il collegamento ai file corrispondenti essere rotto. Tutti i dati bufferizzati vengono scritti e tutti gli input bufferizzati vengono eliminati. La funzione fcloseall restituisce un valore 0 se tutti i file sono stati chiusi correttamente e EOF se è stato rilevato un errore.

+0

Su Linux puoi usare (e controllare a livello di codice) le directory '/ proc/self/fd /' e '/ proc/self/fdinfo /' dall'interno del processo, o '/ proc/$ PID/fd /' etc da al di fuori. '/ proc /' è accessibile da 'pfiles' –

+0

@BasileStarynkevitch Ho letto nel manuale il comando' pfiles' read proc-filesystem –

0
int sig_int(int signo) 
{ 
    if(fdOpen) 
     fclose(fd); 
    abort(); 
} 

Quindi aggiungere questo per main:

static volatile fdOpen = 0; 
static FILE *fd;//I guess 
if(signal(SIGINT,sig_int) == SIG_ERR) 
    printf("signal(SIGINT) error\n"); 

if((fd =fopen("your_file_name","flag_you_need")) != NULL) 
    fdOpen = 1; 

fare questo prima fcolse:

sigset_t newmask,oldmask; 
sigemptyset(&newmask); 
sigaddset(&newmask, SIGINT); 
sigprocmask(SIG_BLOCK, &newmask, &oldmask);//BLOCK SIGINT 

e impostare fdOpen = 0 ; dopo aver chiuso il file normalmente //SIGINT will not interrupt us now.

Poi

sigprocmask(SIG_SETMASK,&oldmask,NULL);//RESET signal mask 

così facciamo alcuni posti di lavoro puliti e quindi uscire dal programma a sig_int.

+0

L'unico problema qui è quando sig_int() viene chiamato dopo il normale 'fclose', ma prima' fdOpen = 0; '. – Inspired

+0

@Inspired Sì, hai ragione. –

4

Mi sembra che ci sia un po 'di confusione nella tua mente.

movimentatori file, usati con fopen, fclose, f... funzioni sono portata processo. I.e., sono validi all'interno dell'applicazione (normalmente).

Due cose possono accadere quando apri un file: ci riesci o no. Se ci riesci, potresti utilizzare il file esclusivamente o condiviso con altri processi. Se fallisci, forse un altro processo sta già utilizzando il file. Cerca _fsopen.

Quando il processo termina, normalmente o interrotto (come con Ctrl+C), il sistema operativo rilascia le risorse associate al processo, prima o poi. Ciò si applica ai gestori di file, alla memoria, ...

Per quanto riguarda la domanda, se l'applicazione termina normalmente o con Ctrl+C, i gestori di file non chiusi verranno rilasciati dal sistema operativo.

Ogni volta che si avvia l'applicazione, è necessario aprire i gestori di file necessari. Il sistema operativo non li manterrà aperti per te.

Problemi correlati