2013-02-14 15 views
5

Mi stavo trastullando con un po 'di codice che stava aprendo, leggendo e modificando un file di testo. Un rapido (semplificato) esempio potrebbe essere:L'uso di "r +" in fopen su windows vs linux

#include <stdio.h> 
int main() 
{ 
    FILE * fp = fopen("test.txt", "r+"); 
    char line[100] = {'\0'}; 
    int count = 0; 
    int ret_code = 0; 
    while(!feof(fp)){ 
     fgets(line, 100, fp); 
     // do some processing on line... 
     count++; 
     if(count == 4) { 
      ret_code = fprintf(fp, "replaced this line\n"); 
      printf("ret code was %d\n", ret_code); 
      perror("Error was: "); 
     } 
    } 
    fclose(fp); 
    return 0; 
} 

Ora su Linux, compilato con gcc (4.6.2) questo codice viene eseguito, e modifica linea 5 del file. Lo stesso codice, eseguito su Windows7 compilato con Visual C++ 2010, esegue e afferma di aver avuto esito positivo (riporta un codice di ritorno di 19 caratteri e perror dice "Nessun errore") ma non riesce a sostituire la linea.

Su Linux il mio file ha le autorizzazioni complete:

-rw-rw-rw- 1 mike users 191 Feb 14 10:11 test.txt 

E per quanto mi riguarda posso dire che sia la stessa su Windows:

test.txt (tasto destro del mouse) -> Proprietà -> Sicurezza
"Consenti" è selezionato per Leggi & Scrivi per utente, sistema e amministratore.

Ottengo gli stessi risultati utilizzando gcc di MinGW su Windows, quindi so che non è una "funzione" di Visual C++.

Mi manca qualcosa di ovvio, o è il fatto che non ottengo errori, ma anche nessun output solo una "funzionalità" non documentata di utilizzare r+ con fopen() su Windows?


EDIT:
Sembra anche a Microsoft's site dicono "R +" dovrebbe aprire per la lettura e scrittura. Hanno anche aggiunto questa nota:

Quando si specifica il tipo di accesso "r +", "w +" o "a +", sono consentiti sia la lettura che la scrittura (il file è detto aperto per "aggiornamento") . Tuttavia, quando si passa dalla lettura alla scrittura, è necessario eseguire un'operazione fflush, fsetpos, fseek o rewind. La posizione corrente può essere specificata per l'operazione fsetpos o fseek, se lo si desidera.

Così ho provato:

 ... 
     if(count == 4) { 
      fflush(fp); 
      ret_code = fprintf(fp, "replaced this line\n"); 
      fflush(fp); 
      printf("ret code was %d\n", ret_code); 
      ... 

inutilmente.

+0

Hai provato a svuotare il flusso utilizzando 'fflush' dopo l'operazione di scrittura? – Cyclonecode

+3

Non sono sicuro se questo è il problema, ma potrebbe essere necessario chiamare 'fseek' quando si passa dalla lettura e scrittura dal file – Hasturkun

+0

@KristerAndersson - sì, appena aggiornato per chiarire Ho visto la nota sul sito MSDN che ti dice dovresti aggiornare il flusso con uno dei 'f ()' così ho provato 'fflush()' ing prima e dopo la scrittura, ma senza dadi. – Mike

risposta

3

Secondo il Linux man page for fopen():

legge e scrive possono essere mescolati sui flussi di lettura/scrittura in qualsiasi ordine. Si noti che ANSI C richiede che una funzione di posizionamento file intervenga tra l'output e l'input, a meno che un'operazione di input non incontri end-of-file. (Se questa condizione non viene soddisfatta, è consentita una lettura su restituire il risultato di scritture diverse da quelle più recenti). Pertanto, è una buona pratica (e talvolta necessaria in Linux) per inserire un fseek (3) o fgetpos (3) operazione tra operazioni di scrittura e lettura su tale flusso. Questa operazione può essere un apparente no-op (come in fseek (..., 0L, SEEK_CUR) chiamato per il suo effetto collaterale di sincronizzazione.

Quindi, si dovrebbe sempre chiamare fseek() (come, ad es.fseek(..., 0, SEEK_CUR)) quando si passa dalla lettura alla scrittura da un file.

+1

Questo era il problema, ed è quello che ottengo per aver letto la documentazione MSDN invece della pagina man. :) Grazie. – Mike

+0

Si noti che la maggior parte dei documenti recenti di MSDN (per VS 2012) è stata aggiornata: http://msdn.microsoft.com/en-us/library/yeby3zcb.aspx –

+0

@MichaelBurr - Buon punto, che non era il più documentazione recente, dovrei aggiornare il mio segnalibro, è da un po 'che non ci sono stato. – Mike

3

Prima di eseguire l'output dopo l'immissione, un fflush() non è valido: è necessario eseguire un'operazione di ricerca. Qualcosa di simile:

fseek(fp, ftell(fp), SEEK_SET); // not fflush(fp); 

dallo standard C99 (7.19.5.3/6 "Il functoin fopen):

Quando un file viene aperto con modalità di aggiornamento ('+' come il secondo o terzo carattere nell'elenco dei valori argomento argomento), sia l'input che l'output possono essere eseguiti sullo stream associato, tuttavia l'output non deve essere seguito direttamente da un input senza una chiamata intermedia a la funzione fflush o una funzione di posizionamento file (fseek, fsetpos, o rewind) e l'input non deve essere seguito direttamente dall'output senza una chiamata intermedia a una funzione di posizionamento file, a meno che l'operazione di immissione non incontri la fine del file.

+0

È divertente, tu dici "fflush() non è buono", ma poi il frammento C99 che hai citato dice: "senza una chiamata interposta alla funzione fflush O a una funzione di posizionamento file". Quindi, proprio lì dice "fflush()' OR 'fseek()'/altre funzioni di posizionamento. – Mike

+2

Questo è per l'output seguito dall'input. Il tuo problema era nell'effettuare l'input seguito dall'output, che ha bisogno di una chiamata di posizionamento file interposta (o EOF). Dirò che questo è un po 'difficile da leggere per avere tutte le condizioni in testa: un tavolo funzionerebbe meglio. –

+0

+1 capito, questo rende il motivo per cui l'ordine conta. Grazie per quell'input. – Mike