Was ist der Unterschied zwischen einem Dateideskriptor und einem Dateizeiger?

Antworten:

144

Ein Dateideskriptor ist ein ganzzahliges "Handle" auf niedriger Ebene, mit dem eine geöffnete Datei (oder ein Socket oder was auch immer) auf Kernelebene unter Linux und anderen Unix-ähnlichen Systemen identifiziert wird.

Sie passieren „nackt“ Dateideskriptoren tatsächliche Unix Anrufe, wie read(), write()und so weiter.

Ein FILEZeiger ist ein C-Standardkonstrukt auf Bibliotheksebene, das zur Darstellung einer Datei verwendet wird. Das FILEumschließt den Dateideskriptor und fügt Pufferung und andere Funktionen hinzu, um die E / A zu vereinfachen.

Sie übergeben FILEZeiger auf Standard-C-Funktionen wie fread()und fwrite().

entspannen
quelle
@nvl: fildes ist sicherlich für Windows verfügbar, z. B. msdn.microsoft.com/en-us/library/z0kc8e3z%28VS.80%29.aspx
kennytm
2
@unwind Was hast du mit "nackten" Dateideskriptoren gemeint? Die verknüpfte Referenz besagt, dass dies fddas erste Argument ist read(). Warum nennst du es nackt?
Geek
3
@Geek Im Vergleich zum FILE *Typ der Standardbibliothek ist der Integer-Dateideskriptor "weniger umbrochen", dh "nackt".
Entspannen Sie
57

Einer ist gepuffert ( FILE *) und der andere nicht. In der Praxis möchten Sie FILE *fast immer verwenden, wenn Sie aus einer "echten" Datei (dh auf dem Laufwerk) lesen, es sei denn, Sie wissen, was Sie tun, oder Ihre Datei ist tatsächlich ein Socket oder so.

Sie können den Dateideskriptor mit FILE *using abrufen fileno()und einen gepufferten FILE *Dateideskriptor mit using öffnenfdopen()

Ben
quelle
12
+1 für den Hinweis auf fileno (), die Organisation der Manpages macht es schwierig, diese zu finden. Gleiches gilt für fdopen ().
BD in Rivenhill
20

Ein Dateideskriptor ist nur eine Ganzzahl, die Sie aus dem POSIX- open()Aufruf erhalten. Mit dem Standard C erhalten fopen()Sie eine FILEStruktur zurück. Die FILEStruktur enthält diesen Dateideskriptor unter anderem wie Dateiende- und Fehleranzeige, Stream-Position usw.

fopen()Wenn Sie also verwenden, erhalten Sie im Vergleich zu eine gewisse Abstraktion open(). Im Allgemeinen sollten Sie verwenden, fopen()da dies portabler ist und Sie alle anderen Standard-C-Funktionen verwenden können, die die FILEStruktur, dh fprintf()und die Familie verwenden.

Es gibt auch keine Leistungsprobleme bei der Verwendung.

Martin Wickman
quelle
8
+1 für die Portabilität. FILE ist Teil der Standard C Library (zurück zu C89 / C90). Dateideskriptoren sind nicht.
Tomlogic
15

Dateideskriptor vs Dateizeiger

Dateideskriptor:

Der Dateideskriptor ist ein ganzzahliger Wert, der vom open()Systemaufruf zurückgegeben wird.

int fd = open (filePath, mode);

  1. Low / Kernel Level Handler.
  2. passe zum Lesen () und Schreiben () von UNIX-Systemaufrufen.
  3. Enthält keine Pufferung und solche Funktionen.
  4. Weniger tragbar und wenig effizient.

Dateizeiger:

Der Dateizeiger ist ein Zeiger auf eine C-Struktur, die von der fopen()Bibliotheksfunktion zurückgegeben wird. Er dient zum Identifizieren einer Datei, zum Umschließen des Dateideskriptors, zum Puffern und für alle anderen Funktionen, die für die E / A-Operation erforderlich sind. Der Dateizeiger ist vom Typ FILE , dessen Definition finden Sie in "/usr/include/stdio.h" . Diese Definition kann von Compiler zu Compiler unterschiedlich sein.

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;
  1. Es ist eine High-Level-Schnittstelle.
  2. Übergeben an die Funktionen fread () und fwrite ().
  3. Beinhaltet Pufferung, Fehleranzeige und EOF-Erkennung usw.
  4. Bietet höhere Portabilität und Effizienz.
Yogeesh HT
quelle
1
Können Sie diesen Anspruch auf höhere Effizienz belegen? Das habe ich noch nie gehört.
Gid
1
Der Anspruch auf "Effizienz" könnte auf Pufferung zurückzuführen sein. Bei einem Dateideskriptor ist jedes Lesen () oder Schreiben () ein Systemaufruf, und jeder Systemaufruf sollte als teuer angesehen werden. Bei einer DATEI * bedeutet das Puffern, dass einige Lese- und Schreibvorgänge keine Systemaufrufe sind.
Mike Spear
12

Möchten Sie Punkte hinzufügen, die nützlich sein könnten.

ÜBER FILE *

  1. kann nicht für die Interprozesskommunikation (IPC) verwendet werden.
  2. Verwenden Sie es, wenn Sie gepufferte E / A für allgemeine Zwecke benötigen (printf, frpintf, snprintf, scanf).
  3. Ich benutze es oft für Debug-Protokolle. Beispiel,

                 FILE *fp;
                 fp = fopen("debug.txt","a");
                 fprintf(fp,"I have reached till this point");
                 fclose(fp);

ÜBER FILE DESCRIPTOR

  1. Es wird im Allgemeinen für IPC verwendet.

  2. Ermöglicht die einfache Steuerung von Dateien auf * nix-Systemen (Geräte, Dateien, Sockets usw.) und ist daher leistungsfähiger als die FILE *.

Akshay Patil
quelle
Können Sie fdopen()nicht Dinge wie IPC und Geräte mit tun FILE*?
Osvein
Eigentlich ja und nein. Sie können IPC nicht mit einrichten und initialisieren FILE*, aber Sie können einen FILE*aus einem Dateideskriptor ( fdopen()) erstellen und später schließen FILE, um den Deskriptor ebenfalls zu schließen. Daher können Sie IPC ausführen, müssen sich jedoch ein wenig mit Dateideskriptoren befassen, um einen direkten IPC zu ermöglichen.
Micah W
3

FILE *ist nützlich , wenn Sie mit Textdateien und Benutzereingabe / Ausgabe arbeiten, weil es Ihnen wie API - Funktionen verwenden kann sprintf(), sscanf(), fgets(), feof()usw.

Die Dateideskriptor-API ist auf niedriger Ebene und ermöglicht daher die Arbeit mit Sockets, Pipes, Dateien mit Speicherzuordnung (und natürlich mit regulären Dateien).

qrdl
quelle
1
+1, weil Sie Dateien mit Speicherzuordnung hinzugefügt haben, da zum Zeitpunkt meines aktuellen Lesens die anderen Antworten bereits geliefert wurden.
ernie.cordell
3

Nur eine Notiz zum Abschluss der Diskussion (falls interessiert) ....

fopenkann unsicher sein, und Sie sollten wahrscheinlich fopen_soder openmit exklusiven gesetzten Bits verwenden. C1X bietet xModi, so können Sie fopenmit Modi "rx", "wx"usw.

Wenn Sie verwenden open, könnten Sie open(..., O_EXCL | O_RDONLY,... )oder in Betracht ziehen open(..., O_CREAT | O_EXCL | O_WRONLY,... ).

Siehe zum Beispiel: Machen Sie keine Annahmen über fopen () und die Dateierstellung .

jww
quelle
Da fopen_ses anscheinend nicht verfügbar ist POSIX, gehe ich davon aus, dass die tragbarste Lösung für open(2)und dann ist fdopen(2). (Fenster beiseite lassen). Was wäre schneller fopen_s()oder open(2)gefolgt von fdopen(2)?
Mihir
1

Systemaufrufe verwenden zum Beispiel meistens den Dateideskriptor readund write. Die Bibliotheksfunktion verwendet die Dateizeiger ( printf, scanf). Bibliotheksfunktionen verwenden jedoch nur interne Systemaufrufe.

Pavunkumar
quelle
Ich bin mir nicht sicher, warum Sie sagen, dass Bibliotheksfunktionen nur interne Systemaufrufe verwenden: Wenn Sie die Standard-CI / O-Funktionen (oder andere für diese Angelegenheit) meinen, bin ich mir nicht sicher, ob dies (allgemein?) Wahr ist. Ansonsten haben Sie das nicht gesagt, daher würde ich gerne sehen, dass die Sprache in Ihrem Beitrag ein wenig aufgeräumt wird. Der letzte Satz verblüfft mich.
ernie.cordell
1

Ich habe hier eine gute Ressource gefunden , die einen umfassenden Überblick über die Unterschiede zwischen den beiden gibt:

Wenn Sie eine Datei eingeben oder ausgeben möchten, haben Sie die Wahl zwischen zwei grundlegenden Mechanismen zur Darstellung der Verbindung zwischen Ihrem Programm und der Datei: Dateideskriptoren und Streams. Dateideskriptoren werden als Objekte vom Typ int dargestellt, während Streams als FILE * -Objekte dargestellt werden.

Dateideskriptoren bieten eine primitive Schnittstelle für Eingabe- und Ausgabeoperationen auf niedriger Ebene. Sowohl Dateideskriptoren als auch Streams können eine Verbindung zu einem Gerät (z. B. einem Terminal) oder einer Pipe oder einem Socket für die Kommunikation mit einem anderen Prozess sowie eine normale Datei darstellen. Wenn Sie jedoch Steuerungsvorgänge ausführen möchten, die für einen bestimmten Gerätetyp spezifisch sind, müssen Sie einen Dateideskriptor verwenden. Es gibt keine Möglichkeit, Streams auf diese Weise zu verwenden. Sie müssen auch Dateideskriptoren verwenden, wenn Ihr Programm Eingaben oder Ausgaben in speziellen Modi ausführen muss, z. B. nicht blockierende (oder abgefragte) Eingaben (siehe Dateistatus-Flags).

Streams bieten eine übergeordnete Schnittstelle, die über den primitiven Dateideskriptorfunktionen liegt. Die Stream-Oberfläche behandelt alle Arten von Dateien ziemlich ähnlich - die einzige Ausnahme sind die drei Pufferstile, die Sie auswählen können (siehe Stream-Pufferung).

Der Hauptvorteil der Verwendung der Stream-Schnittstelle besteht darin, dass der Satz von Funktionen zum Ausführen tatsächlicher Eingabe- und Ausgabeoperationen (im Gegensatz zu Steueroperationen) für Streams viel umfangreicher und leistungsfähiger ist als die entsprechenden Funktionen für Dateideskriptoren. Die Dateideskriptor-Schnittstelle bietet nur einfache Funktionen zum Übertragen von Zeichenblöcken, aber die Stream-Schnittstelle bietet auch leistungsstarke formatierte Eingabe- und Ausgabefunktionen (printf und scanf) sowie Funktionen für die zeichen- und zeilenorientierte Eingabe und Ausgabe.

Da Streams in Form von Dateideskriptoren implementiert sind, können Sie den Dateideskriptor aus einem Stream extrahieren und Operationen auf niedriger Ebene direkt am Dateideskriptor ausführen. Sie können eine Verbindung auch zunächst als Dateideskriptor öffnen und dann einen Stream erstellen, der diesem Dateideskriptor zugeordnet ist.

Im Allgemeinen sollten Sie Streams anstelle von Dateideskriptoren verwenden, es sei denn, Sie möchten eine bestimmte Operation ausführen, die nur für einen Dateideskriptor ausgeführt werden kann. Wenn Sie ein Anfänger sind und sich nicht sicher sind, welche Funktionen Sie verwenden sollen, empfehlen wir Ihnen, sich auf die formatierten Eingabefunktionen (siehe Formatierte Eingabe) und die formatierten Ausgabefunktionen (siehe Formatierte Ausgabe) zu konzentrieren.

Wenn Sie Bedenken hinsichtlich der Portabilität Ihrer Programme auf andere Systeme als GNU haben, sollten Sie sich auch darüber im Klaren sein, dass Dateideskriptoren nicht so portabel sind wie Streams. Sie können davon ausgehen, dass jedes System, auf dem ISO C ausgeführt wird, Streams unterstützt, aber Nicht-GNU-Systeme unterstützen möglicherweise überhaupt keine Dateideskriptoren oder implementieren nur eine Teilmenge der GNU-Funktionen, die mit Dateideskriptoren arbeiten. Die meisten Dateideskriptorfunktionen in der GNU C-Bibliothek sind jedoch im POSIX.1-Standard enthalten.

Suraj Jain
quelle