C fopen vs ouvert

219

Y a-t-il une raison (autre que syntaxique) que vous voudriez utiliser

FILE *fdopen(int fd, const char *mode);

ou

FILE *fopen(const char *path, const char *mode);

au lieu de

int open(const char *pathname, int flags, mode_t mode);

lors de l'utilisation de C dans un environnement Linux?

LJM
la source
Voulez-vous dire fdopenet openou fopenet open?
user7116
Vous ne voulez pas dire fopen, pas fdopen?
Omnifarious
9
fopenfait partie de la bibliothèque C standard, openn'est pas. À utiliser fopenlors de l'écriture de code portable.
Aziz
Oui, je voulais dire fopen. Je viens de le mettre à jour, mais je pense que le même principe s'applique.
LJM
6
@Aziz, cependant, openest une fonction POSIX.
dreamlax

Réponses:

242

Premièrement, il n'y a pas de raison particulièrement valable d'utiliser fdopensi fopenc'est une option et openc'est l'autre choix possible. Vous ne devriez pas avoir utilisé openpour ouvrir le fichier en premier lieu si vous voulez un fichier FILE *. Donc, l'inclusion fdopendans cette liste est incorrecte et déroutante car elle ne ressemble pas beaucoup aux autres. Je vais maintenant passer à l'ignorer car la distinction importante ici est entre une norme CFILE * et un descripteur de fichier spécifique au système d'exploitation.

Il y a quatre raisons principales d'utiliser fopenau lieu de open.

  1. fopen vous offre un IO de mise en mémoire tampon qui peut s'avérer beaucoup plus rapide que ce que vous faites avec open .
  2. fopen effectue la traduction de fin de ligne si le fichier n'est pas ouvert en mode binaire, ce qui peut être très utile si votre programme est jamais porté vers un environnement non Unix (bien que le monde semble converger sur LF uniquement (sauf la mise en réseau textuelle IETF) protocoles tels que SMTP et HTTP et autres)).
  3. A FILE *vous donne la possibilité d'utiliser fscanfet d'autres fonctions stdio.
  4. Il se peut qu'un jour, votre code doive être porté sur une autre plate-forme qui prend uniquement en charge ANSI C et ne prend pas en charge la openfonction.

À mon avis, la fin de la ligne de traduction gêne plus souvent votre chemin que vous aide, et l'analyse de fscanfest si faible que vous finissez inévitablement par la jeter en faveur de quelque chose de plus utile.

Et la plupart des plates-formes qui prennent en charge C ont une openfonction.

Cela laisse la question tampon. Dans les endroits où vous lisez ou écrivez principalement un fichier de manière séquentielle, la prise en charge de la mise en mémoire tampon est vraiment utile et améliore considérablement la vitesse. Mais cela peut entraîner des problèmes intéressants dans lesquels les données ne se retrouvent pas dans le fichier lorsque vous vous attendez à ce qu'elles soient là. Vous devez vous souvenir de fcloseou fflushaux moments appropriés.

Si vous faites des recherches (alias fsetposou dont fseekla seconde est légèrement plus délicate à utiliser de manière conforme aux normes), l'utilité de la mise en mémoire tampon diminue rapidement.

Bien sûr, mon parti pris est que j'ai tendance à beaucoup travailler avec des sockets, et il y a le fait que vous voulez vraiment faire des E / S non bloquantes (qui FILE *ne supportent pas du tout de manière raisonnable) sans tampon du tout et souvent ont des exigences d'analyse complexes colorent vraiment mes perceptions.

Très varié
la source
4
Je ne vais pas remettre en question vos expériences, mais j'aimerais vous entendre développer un peu à ce sujet. Pour quel type d'applications pensez-vous que la mise en mémoire tampon intégrée gêne? Quel est le problème exactement?
Emil H
1
N'a pas vu le dernier paragraphe. Point valide, à mon humble avis. Pour autant que je sache, la question concernait le fichier IO.
Emil H
7
Pour clarifier le moment où la mise en mémoire tampon gêne. C'est lorsque vous utilisez la recherche. La lecture suivante avec tout ce que commande ( fgets, fgetc, fscanf, fread), lira toujours la taille entière du tampon (4K, 8K ou tout ce que vous définissez). En utilisant les E / S directes, vous pouvez éviter cela. Dans ce cas, il est encore préférable d'utiliser preadau lieu d'une paire de recherche / lecture (1 syscall au lieu de 2).
Patrick Schlüter
2
La gestion des appels interrompus read()et write()est une cinquième raison pratique d'utiliser la famille de fonctions libc.
nccc
3
@ m-ric: Eh bien, c'est une question quelque peu indépendante, mais oui. Toutes les plates-formes qui prennent en ioctlcharge prennent également en charge l' filenoappel qui prend un FILE *et renvoie un numéro qui peut être utilisé dans un ioctlappel. Soyez prudent cependant. FILE *les appels associés peuvent interagir de manière surprenante avec l'utilisation de ioctlpour modifier quelque chose au sujet du descripteur de fichier sous-jacent.
Omnifarious
53

open()est un appel os de bas niveau. fdopen()convertit un descripteur de fichier de niveau os en abstraction FILE de niveau supérieur du langage C. fopen()appelle open()en arrière-plan et vous donne directement un pointeur FILE.

Il y a plusieurs avantages à utiliser des objets FILE plutôt que des descripteurs de fichiers bruts, ce qui inclut une plus grande facilité d'utilisation mais également d'autres avantages techniques tels que la mise en mémoire tampon intégrée. En particulier, la mise en mémoire tampon se traduit généralement par un avantage de performance appréciable.

Emil H
la source
3
Y a-t-il des inconvénients à utiliser les versions "f ..." tamponnées d'Open?
LJM
5
@L. Moser, oui, lorsque vous mettez déjà les données en mémoire tampon, et donc le tampon supplémentaire ajoute une copie inutile et une surcharge de mémoire.
Michael Aaron Safyan
6
en fait, il y a d'autres inconvénients. fopen()ne fournit pas le même niveau de contrôle lors de l'ouverture de fichiers, par exemple créer des autorisations, des modes de partage, etc. généralement open()et les variantes offrent beaucoup plus de contrôle, proche de ce que le système d'exploitation fournit réellement
Matt Joiner
2
Il y a aussi les cas extrêmes où vous mmapenregistrez le fichier et effectuez des modifications avec des E / S normales (aussi incroyable que cela puisse paraître, nous le faisons en fait dans notre projet et pour de bonnes raisons), la mise en mémoire tampon serait un obstacle.
Patrick Schlüter
Vous pouvez également vouloir utiliser d'autres fonctions du système, comme utiliser open () pour précharger des fichiers dans le cache de page via readahead (). Je suppose que la règle générale est "utilisez fopen à moins que vous ayez absolument besoin de open ()", open () vous permet en fait de faire des trucs fantaisistes (paramétrer / ne pas paramétrer O_ATIME et similaire).
Tomas Pruzina
34

fopen vs open en C

1) fopenest une fonction de bibliothèque alors qu'il opens'agit d'un appel système .

2) fopenfournit des entrées-sorties tamponnées qui sont plus rapides que celles openqui ne le sont pas .

3) fopenest portable sans openêtre portable ( ouvert est spécifique à l'environnement ).

4) fopenrenvoie un pointeur sur une structure FILE (FILE *) ; openrenvoie un entier qui identifie le fichier.

5) A FILE *vous donne la possibilité d'utiliser fscanf et d'autres fonctions stdio.

Yogeesh HT
la source
9
openest un standard POSIX, donc il est assez portable
osvein
12

Sauf si vous faites partie du 0,1% des applications où l'utilisation openest un réel avantage en termes de performances, il n'y a vraiment aucune bonne raison de ne pas l'utiliser fopen. En ce qui fdopenconcerne, si vous ne jouez pas avec des descripteurs de fichiers, vous n'avez pas besoin de cet appel.

Bâton avec fopenet sa famille de méthodes ( fwrite, fread, fprintf, et al) et vous serez très satisfaits. Tout aussi important, d'autres programmeurs seront satisfaits de votre code.

user7116
la source
11

Si vous en avez un FILE *, vous pouvez utiliser des fonctions comme fscanf, fprintfet fgetsetc. Si vous avez juste le descripteur de fichier, vous avez des routines d'entrée et de sortie limitées (mais probablement plus rapides) read, writeetc.

dreamlax
la source
7

Utiliser open, read, write signifie que vous devez vous soucier des interaptions de signaux.

Si l'appel a été interrompu par un gestionnaire de signal, les fonctions renvoient -1 et définissent errno sur EINTR.

Donc, la bonne façon de fermer un fichier serait

while (retval = close(fd), retval == -1 && ernno == EINTR) ;
digy
la source
4
Pour close, cela dépend du système d'exploitation. Il est incorrect de faire la boucle sur Linux, AIX et certains autres systèmes d'exploitation.
strcat
De plus, l'utilisation de la lecture et de l'écriture souffrira du même problème, c'est-à-dire qu'elles peuvent être interrompues par un signal avant de traiter entièrement l'entrée / sortie et le programmeur doit gérer de telles situations, tandis que fread et fwrite gèrent bien les interruptions de signal.
Marcelo
6

open()est un appel système et spécifique aux systèmes basés sur Unix et il renvoie un descripteur de fichier. Vous pouvez écrire dans un descripteur de fichier à l'aide d' write()un autre appel système.
fopen()est un appel de fonction ANSI C qui renvoie un pointeur de fichier et il est portable sur d'autres systèmes d'exploitation. Nous pouvons écrire dans un pointeur de fichier en utilisantfprintf .

Sous Unix:
vous pouvez obtenir un pointeur de fichier à partir du descripteur de fichier en utilisant:

fP = fdopen(fD, "a");

Vous pouvez obtenir un descripteur de fichier à partir du pointeur de fichier en utilisant:

fD = fileno (fP);
Arun Chettoor
la source
4

open () sera appelé à la fin de chacune des fonctions de la famille fopen () . open () est un appel système et fopen () sont fournis par les bibliothèques comme des fonctions d'encapsulation pour un utilisateur facile à utiliser

theadnangondal
la source
2

J'ai changé pour ouvrir () de fopen () pour mon application, car fopen provoquait des doubles lectures à chaque fois que j'exécutais fopen fgetc. Les doubles lectures perturbaient ce que j'essayais d'accomplir. open () semble faire ce que vous lui demandez.

Ersatz Splatt
la source
2

Cela dépend également des drapeaux qui doivent être ouverts. En ce qui concerne l'utilisation pour l'écriture et la lecture (et la portabilité), f * devrait être utilisé, comme expliqué ci-dessus.

Mais si vous voulez spécifier plus que des indicateurs standard (comme les indicateurs rw et append), vous devrez utiliser une API spécifique à la plate-forme (comme POSIX open) ou une bibliothèque qui résume ces détails. La norme C n'a pas de tels indicateurs.

Par exemple, vous souhaiterez peut-être ouvrir un fichier, uniquement s'il se ferme. Si vous ne spécifiez pas l'indicateur de création, le fichier doit exister. Si vous ajoutez exclusif à créer, il ne créera le fichier que s'il n'existe pas. Il y en a bien d'autres.

Par exemple, sur les systèmes Linux, il existe une interface LED exposée via sysfs. Il expose la luminosité de la led à travers un fichier. Écrire ou lire un nombre sous forme de chaîne allant de 0 à 255. Bien sûr, vous ne voulez pas créer ce fichier et n'y écrire que s'il existe. La chose cool maintenant: utilisez fdopen pour lire / écrire ce fichier en utilisant les appels standard.

Ritualmaster
la source
0

ouvrir un fichier en utilisant fopen
avant de pouvoir lire (ou écrire) des informations depuis (vers) un fichier sur un disque, nous devons ouvrir le fichier. pour ouvrir le fichier, nous avons appelé la fonction fopen.

1.firstly it searches on the disk the file to be opened.
2.then it loads the file from the disk into a place in memory called buffer.
3.it sets up a character pointer that points to the first character of the buffer.

ce mode de comportement de la fonction fopen
il y a des causes pendant le processus de mise en mémoire tampon, il peut expirer. Ainsi, tout en comparant l' appel système fopen ( E / S de haut niveau) à l' ouverture (E / S de bas niveau), il est plus rapide et plus approprié que fopen .

prashad
la source
est ouvert plus rapidement que fopen?
obayhan
oui, open est l'appel système, qui est plus rapide que fopen - comparativement @obayhan
prashad