C'è qualche ragione ordinaria per usare open () al posto di fopen ()?
Domanda
che sto facendo un piccolo progetto in C, dopo un lungo periodo di tempo abbastanza lontano da esso. Questi capita di includere alcuni la gestione dei file. Ho notato che in vari documenti che ci sono funzioni che restituiscono maniglie FILE *
e altri che ritornano (small integer) descrittori. Entrambe le serie di funzioni offrono gli stessi servizi di base di cui ho bisogno in modo che davvero non importa che uso.
Ma io sono curioso di sapere la saggezza collezione:? E 'meglio usare fopen()
e amici, o open()
e amici
Modifica Dal momento che qualcuno ha detto tamponata vs dispositivi senza buffer e di accesso, devo aggiungere che una parte di questo piccolo progetto sarà scrittura di un driver in userspace filesystem sotto FUSE. Così l'accesso a livello file potrebbe facilmente essere su un dispositivo (ad esempio un CD-ROM o un drive SCSI) come su un "file" (vale a dire l'immagine).
Soluzione
L'obiezione che "fopen" è portatile e "aperto" è non è fasullo.
fopen fa parte della libc, aperta è una chiamata di sistema POSIX.
Ognuno di essi è più portabile come il luogo da cui provengono.
I / O per fopen'ed file è (è necessario assumere che sia, e per scopi pratici, è) tamponato da libc, descrittori di file aperto) 'ed (non sono tamponata da libc (possono anche essere, e di solito sono tamponata nel filesystem -. ma non tutto si apre () è un file su un filesystem
Qual è il punto di fopen'ing, per esempio, un nodo di dispositivo come / dev / sg0, per esempio, o / dev / tty0 ... Che cosa hai intenzione di fare? Si sta andando a fare un'ioctl su un file *? Buona fortuna.
Forse si vuole aprire con alcune bandiere come O_DIRECT - non ha senso con fopen ()
.Altri suggerimenti
E 'meglio usare open () se si sta attaccando a sistemi Unix-like e come si potrebbe:
- Avere un controllo più fine su unix bit dei permessi sulla creazione del file.
- Utilizzare le funzioni di livello inferiore, come lettura / scrittura / mmap a differenza del C buffer flusso di funzioni di I / O.
- descrittore di file Usa (fd) pianificazione basata IO (sondaggio, selezionare, ecc) Naturalmente, è possibile ottenere un fd da un file * utilizzando fileno (), ma bisogna fare attenzione a non mescolare FILE * funzioni di flusso basati con funzioni basate fd.
- Aprire qualsiasi dispositivo speciale (non un file normale)
E 'meglio utilizzare fopen / fread / fwrite per la massima portabilità, in quanto questi sono funzioni standard C, le funzioni che ho citato sopra non sono.
opere fopen a un livello superiore a quello aperto .... fopen si restituisce un puntatore a file di flusso che è simile a l'astrazione flusso di leggere in C ++
ritorna aprirà un descrittore di file per il file aperto ... Non fornisce un'astrazione torrente e si è responsabile per la gestione dei bit e byte se stessi ... Questo è a un livello inferiore rispetto a fopen
stream stdio sono tamponati, mentre i descrittori di file aperti () non lo sono. Dipende da quello che vi serve. È inoltre possibile creare una dall'altra:
int fileno (FILE * stream) restituisce il descrittore di file per un file *, FILE * fdopen (int Fildes, const char * mode) crea un file * da un descrittore di file.
Fate attenzione quando mescolanza tamponata e non tamponata IO, dal momento che si perde ciò che è nel vostro buffer quando si Non dilavare con fflush ().
Sì. Quando avete bisogno di un manico di basso livello.
Su sistemi operativi UNIX, si può generalmente scambiare file handle e prese.
Inoltre, a basso livello maniglie fanno per una migliore compatibilità ABI di puntatori a file.
Di solito, si dovrebbe favorire utilizzando la libreria standard (fopen). Tuttavia, ci sono occasioni in cui sarà necessario utilizzare l'open direttamente.
Un esempio che mi viene in mente è quello di risolvere un bug in una versione precedente di Solaris che hanno reso fopen fallire dopo 256 file erano aperti. Questo è stato perché hanno usato erroniously un unsigned char per il campo fd nella loro attuazione struct FILE invece di un int. Ma questo era un caso molto specifico.
read () e write () usare senza buffer di I / O. ( fd : intero descrittore di file)
fread () e fwrite () uso buffer di I / O. ( FILE * puntatore struttura)
Dati binari scritti in un tubo con write () non possono in grado di leggere i dati binari con fread () , a causa di allineamenti di byte, dimensioni variabili, ecc E 'una merda-shoot.
La maggior parte di basso livello di codice di driver di periferica utilizza le chiamate di I / O senza buffer.
La maggior parte a livello di applicazione I / O utilizza tamponato.
L'uso delle file * e le sue funzioni associate è OK su base macchina per macchina: ma si perde la portabilità su altre architetture in lettura e scrittura di dati binari. fwrite () è tamponato I / O e può portare a risultati non attendibili se scritto per un architettura a 64 bit e corsa su un 32bit; o (Windows / Linux). La maggior parte sistemi operativi hanno macro di compatibilità all'interno del proprio codice per evitare questo.
Per I binari di basso livello portabilità / O read () e write () garanzia lo stesso binario di lettura e scrittura quando viene compilato su architetture diverse. La cosa fondamentale è quello di scegliere un modo o l'altro ed essere coerenti al riguardo, tutta la suite binario.
<stdio.h> // mostly FILE* some fd input/output parameters for compatibility
// gives you a lot of helper functions -->
List of Functions
Function Description
───────────────────────────────────────────────────────────────────
clearerr check and reset stream status
fclose close a stream
fdopen stream open functions //( fd argument, returns FILE*) feof check and reset stream status
ferror check and reset stream status
fflush flush a stream
fgetc get next character or word from input stream
fgetpos reposition a stream
fgets get a line from a stream
fileno get file descriptor // (FILE* argument, returns fd)
fopen stream open functions
fprintf formatted output conversion
fpurge flush a stream
fputc output a character or word to a stream
fputs output a line to a stream
fread binary stream input/output
freopen stream open functions
fscanf input format conversion
fseek reposition a stream
fsetpos reposition a stream
ftell reposition a stream
fwrite binary stream input/output
getc get next character or word from input stream
getchar get next character or word from input stream
gets get a line from a stream
getw get next character or word from input stream
mktemp make temporary filename (unique)
perror system error messages
printf formatted output conversion
putc output a character or word to a stream
putchar output a character or word to a stream
puts output a line to a stream
putw output a character or word to a stream
remove remove directory entry
rewind reposition a stream
scanf input format conversion
setbuf stream buffering operations
setbuffer stream buffering operations
setlinebuf stream buffering operations
setvbuf stream buffering operations
sprintf formatted output conversion
sscanf input format conversion
strerror system error messages
sys_errlist system error messages
sys_nerr system error messages
tempnam temporary file routines
tmpfile temporary file routines
tmpnam temporary file routines
ungetc un-get character from input stream
vfprintf formatted output conversion
vfscanf input format conversion
vprintf formatted output conversion
vscanf input format conversion
vsprintf formatted output conversion
vsscanf input format conversion
Quindi, per l'uso di base io personalmente utilizzare quanto sopra senza mescolare linguaggi troppo.
Al contrario,
<unistd.h> write()
lseek()
close()
pipe()
<sys/types.h>
<sys/stat.h>
<fcntl.h> open()
creat()
fcntl()
all use file descriptors.
Questi forniscono un controllo granulare su lettura e la scrittura di byte (Consigliato per i dispositivi speciali e FIFO (tubi)).
Quindi, di nuovo, di utilizzare ciò che è necessario, ma mantenere coerenti nei vostri idiomi e interfacce. Se la maggior parte del codice di base utilizza una modalità, utilizzare anche questo, a meno che non ci sia un vero e proprio motivo per non. Entrambi i gruppi di I / O funzioni di libreria sono estremamente affidabili e utilizzato milioni di volte al giorno.
Nota - Se si sta interfacciando C di I / O con un altro linguaggio, (Perl, Python, Java, C #, Lua ...) Check out ciò che gli sviluppatori di queste lingue consigliamo prima di scrivere il codice C e risparmiare qualche problema.
fopen e le sue cugine sono tamponate. aperto, leggere e scrivere non tamponata. L'applicazione può o non può cura.
fprintf e scanf hanno un'API più ricca che permette di leggere e scrivere file di testo formattati. leggere e scrivere utilizzare le matrici fondamentali di byte. Conversioni e formattazioni devono essere fatti a mano.
La differenza tra descrittori di file e (FILE *) è davvero irrilevante.
Randy