Risposte:
Un descrittore di file è un "handle" intero di basso livello utilizzato per identificare un file aperto (o socket, o qualsiasi altra cosa) a livello di kernel, in Linux e altri sistemi Unix-like.
Si passano descrittori di file "nudi" alle effettive chiamate Unix, come read()
, write()
e così via.
Un FILE
puntatore è un costrutto a livello di libreria standard C, utilizzato per rappresentare un file. Il FILE
wrapping del descrittore di file e aggiunge buffering e altre funzionalità per rendere più facile l'I / O.
Si passano i FILE
puntatori a funzioni C standard come fread()
e fwrite()
.
fd
è il primo argomento per read()
. Perché lo chiami nudo?
FILE *
tipo della libreria standard , il descrittore di file intero è "meno impacchettato", cioè "nudo".
Uno è bufferizzato ( FILE *
) e l'altro no. In pratica, vuoi usare FILE *
quasi sempre quando stai leggendo da un file 'reale' (cioè sul disco), a meno che tu non sappia cosa stai facendo oa meno che il tuo file non sia effettivamente un socket o giù di lì ..
Puoi ottenere il descrittore di file da FILE *
using fileno()
e puoi aprire un buffer FILE *
da un descrittore di file usandofdopen()
Un descrittore di file è solo un numero intero che ottieni dalla open()
chiamata POSIX . Usando lo standard C fopen()
ottieni FILE
indietro una struttura. La FILE
struttura contiene questo descrittore di file tra le altre cose come la fine del file e l'indicatore di errore, la posizione del flusso ecc.
Quindi l'utilizzo fopen()
ti dà una certa quantità di astrazione rispetto a open()
. In generale dovresti usarlo fopen()
poiché è più portabile e puoi usare tutte le altre funzioni C standard che usano la FILE
struttura, cioè, fprintf()
e la famiglia.
Non ci sono problemi di prestazioni nell'utilizzo di entrambi.
Descrittore di file vs puntatore di file
Descrittore di file:
File Descriptor è un valore intero restituito dalla open()
chiamata di sistema.
int fd = open (filePath, mode);
Puntatore file:
File Pointer è un puntatore a una struttura C restituita dalla fopen()
funzione di libreria, che viene utilizzata per identificare un file, avvolgere il descrittore di file, funzionalità di buffering e tutte le altre funzionalità necessarie per le operazioni di I / O. Il puntatore di file è di tipo FILE , la cui definizione può essere trovato in "/usr/include/stdio.h" . Questa definizione può variare da un compilatore all'altro.
FILE *fp = fopen (filePath, mode);
// A FILE Structure returned by fopen
typedef struct
{
unsigned char *_ptr;
int _cnt;
unsigned char *_base;
unsigned char *_bufendp;
short _flag;
short _file;
int __stdioid;
char *__newbase;
#ifdef _THREAD_SAFE
void *_lock;
#else
long _unused[1];
#endif
#ifdef __64BIT__
long _unused1[4];
#endif /* __64BIT__ */
} FILE;
Vuoi aggiungere punti che potrebbero essere utili.
DI FILE *
Lo uso molte volte per i log di debug. esempio,
FILE *fp;
fp = fopen("debug.txt","a");
fprintf(fp,"I have reached till this point");
fclose(fp);
DI FILE DESCRIPTOR
Viene generalmente utilizzato per IPC.
Fornisce un controllo di basso livello ai file sui sistemi * nix (dispositivi, file, socket, ecc.), Quindi più potente del FILE *
.
fdopen()
per fare cose come IPC e dispositivi con FILE*
?
FILE*
, ma è possibile creare un FILE*
da un descrittore di file ( fdopen()
) e la successiva chiusura di FILE
chiuderà anche il descrittore. Pertanto, puoi eseguire IPC, ma devi occuparti un po 'dei descrittori di file per facilitare qualsiasi IPC diretto.
FILE *
è più utile quando si lavora con i file di testo e user input / output, perché consente di utilizzare le funzioni API come sprintf()
, sscanf()
, fgets()
, feof()
etc.
L'API del descrittore di file è di basso livello, quindi consente di lavorare con socket, pipe, file mappati in memoria (e file normali, ovviamente).
Solo una nota per concludere la discussione (se interessati) ....
fopen
può essere insicuro e probabilmente dovresti usare fopen_s
o open
con set di bit esclusivi. C1X sta offrendo x
modalità, in modo da poter fopen
con i modi "rx"
, "wx"
e così via
Se usi open
, potresti considerare open(..., O_EXCL | O_RDONLY,... )
o open(..., O_CREAT | O_EXCL | O_WRONLY,... )
.
Vedere, ad esempio, Non fare supposizioni su fopen () e sulla creazione di file .
fopen_s
che non sembra essere disponibile con POSIX
, presumo che l'anima più portatile sarebbe quella di open(2)
e poi fdopen(2)
. (lasciando da parte le finestre). Inoltre, cosa sarebbe più veloce fopen_s()
o open(2)
seguito da fdopen(2)
?
Le chiamate di sistema utilizzano principalmente descrittori di file, ad esempio read
e write
. La funzione di libreria utilizzerà i puntatori di file ( printf
, scanf
). Tuttavia, le funzioni di libreria utilizzano solo chiamate di sistema interne.
Ho trovato una buona risorsa qui , fornendo una panoramica di alto livello delle differenze tra i due:
Quando si desidera eseguire l'input o l'output in un file, è possibile scegliere tra due meccanismi di base per rappresentare la connessione tra il programma e il file: descrittori di file e flussi. I descrittori di file sono rappresentati come oggetti di tipo int, mentre i flussi sono rappresentati come oggetti FILE *.
I descrittori di file forniscono un'interfaccia primitiva di basso livello per le operazioni di input e output. Sia i descrittori di file che i flussi possono rappresentare una connessione a un dispositivo (come un terminale) o una pipe o un socket per la comunicazione con un altro processo, nonché un file normale. Tuttavia, se si desidera eseguire operazioni di controllo specifiche per un particolare tipo di dispositivo, è necessario utilizzare un descrittore di file; non ci sono strutture per utilizzare i flussi in questo modo. È inoltre necessario utilizzare i descrittori di file se il programma deve eseguire l'input o l'output in modalità speciali, come l'input non bloccante (o con polling) (vedere Flag di stato del file).
I flussi forniscono un'interfaccia di livello superiore, sovrapposta alle funzionalità primitive del descrittore di file. L'interfaccia stream tratta tutti i tipi di file praticamente allo stesso modo, l'unica eccezione sono i tre stili di buffering che puoi scegliere (vedi Stream Buffering).
Il vantaggio principale dell'utilizzo dell'interfaccia stream è che l'insieme di funzioni per eseguire effettive operazioni di input e output (al contrario delle operazioni di controllo) sui flussi è molto più ricco e potente delle corrispondenti funzionalità per i descrittori di file. L'interfaccia del descrittore di file fornisce solo semplici funzioni per il trasferimento di blocchi di caratteri, ma l'interfaccia stream fornisce anche potenti funzioni di input e output formattati (printf e scanf), nonché funzioni per input e output orientati ai caratteri e alla riga.
Poiché i flussi sono implementati in termini di descrittori di file, è possibile estrarre il descrittore di file da un flusso ed eseguire operazioni di basso livello direttamente sul descrittore di file. È inoltre possibile aprire inizialmente una connessione come descrittore di file e quindi creare un flusso associato a tale descrittore di file.
In generale, dovresti continuare a usare flussi piuttosto che descrittori di file, a meno che non ci sia qualche operazione specifica che desideri fare che può essere eseguita solo su un descrittore di file. Se sei un programmatore principiante e non sei sicuro di quali funzioni utilizzare, ti suggeriamo di concentrarti sulle funzioni di input formattato (vedi Input formattato) e sulle funzioni di output formattato (vedi Output formattato).
Se sei preoccupato per la portabilità dei tuoi programmi su sistemi diversi da GNU, dovresti anche essere consapevole che i descrittori di file non sono portabili come gli stream. Ci si può aspettare che qualsiasi sistema che esegue ISO C supporti i flussi, ma i sistemi non GNU potrebbero non supportare affatto i descrittori di file, o potrebbero implementare solo un sottoinsieme delle funzioni GNU che operano sui descrittori di file. Tuttavia, la maggior parte delle funzioni del descrittore di file nella libreria GNU C sono incluse nello standard POSIX.1.