¿Cuál es la diferencia entre un descriptor de archivo y un puntero de archivo?

Respuestas:

144

Un descriptor de archivo es un "identificador" entero de bajo nivel que se usa para identificar un archivo abierto (o socket, o lo que sea) a nivel del kernel, en Linux y otros sistemas similares a Unix.

Pasa descriptores de archivos "desnudos" a llamadas Unix reales, como read(), write()etc.

Un FILEpuntero es una construcción de nivel de biblioteca estándar de C, que se utiliza para representar un archivo. La FILEenvuelve el descriptor de archivo y añade tampón y otras características para hacer de E / S más fácil.

Pasa FILEpunteros a funciones C estándar como fread()y fwrite().

relajarse
fuente
@nvl: fildes seguramente está disponible para Windows, por ejemplo, msdn.microsoft.com/en-us/library/z0kc8e3z%28VS.80%29.aspx
kennytm
2
@unwind ¿Qué quisiste decir con descriptores de archivo "desnudos"? La referencia vinculada dice que fdes el primer argumento de read(). ¿Por qué lo llamas desnudo?
Geek
3
@Geek En comparación con el FILE *tipo de biblioteca estándar , el descriptor de archivo entero está "menos envuelto", es decir, "desnudo".
relajarse el
57

Uno está almacenado en búfer ( FILE *) y el otro no. En la práctica, querrá usar FILE *casi siempre cuando esté leyendo de un archivo 'real' (es decir, en la unidad), a menos que sepa lo que está haciendo o que su archivo sea en realidad un socket o algo así.

Puede obtener el descriptor de archivo FILE *usando fileno()y puede abrir un búfer FILE *desde un descriptor de archivo usandofdopen()

Ben
fuente
12
+1 para señalar fileno (), la organización de las páginas de manual hace que sea difícil de encontrar. Lo mismo para fdopen ().
BD en Rivenhill
20

Un descriptor de archivo es solo un número entero que se obtiene de la open()llamada POSIX . Usando el estándar C fopen()obtienes una FILEestructura. La FILEestructura contiene este descriptor de archivo, entre otras cosas, como el indicador de fin de archivo y error, la posición de la secuencia, etc.

Por lo tanto, usar fopen()le brinda una cierta cantidad de abstracción en comparación con open(). En general, debería usarlo, fopen()ya que es más portátil y puede usar todas las demás funciones estándar de C que usan la FILEestructura, es decir, fprintf()y la familia.

No hay problemas de rendimiento al usar ninguno.

Martin Wickman
fuente
8
+1 para mejorar la portabilidad. ARCHIVO es parte de la Biblioteca C estándar (de regreso a C89 / C90); los descriptores de archivo no lo son.
tomlogic
15

Descriptor de archivo vs puntero de archivo

Descriptor de archivo:

El descriptor de archivo es un valor entero devuelto por una open()llamada al sistema.

int fd = open (filePath, mode);

  1. Controlador de nivel bajo / kernel.
  2. passe para leer () y escribir () de llamadas al sistema UNIX.
  3. No incluye almacenamiento en búfer ni características similares.
  4. Menos portátil y carece de eficiencia.

Puntero de archivo:

File Pointer es un puntero a una estructura C devuelta por la fopen()función de biblioteca, que se utiliza para identificar un archivo, envolver el descriptor de archivo, la funcionalidad de almacenamiento en búfer y todas las demás funciones necesarias para la operación de E / S. El puntero de archivo es de tipo FILE , cuya definición se puede encontrar en "/usr/include/stdio.h" . Esta definición puede variar de un compilador a otro.

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 una interfaz de alto nivel.
  2. Pasado a las funciones fread () y fwrite ().
  3. Incluye almacenamiento en búfer, indicación de errores y detección de EOF, etc.
  4. Proporciona una mayor portabilidad y eficiencia.
Yogeesh HT
fuente
1
¿Puede respaldar esa afirmación de mayor eficiencia? Nunca escuché eso.
Gid
1
La afirmación de "eficiencia" podría deberse al almacenamiento en búfer. Con un descriptor de archivo, cada lectura () o escritura () es una llamada al sistema, y ​​cada llamada al sistema debe considerarse cara. Con un ARCHIVO *, el almacenamiento en búfer significa que algunas lecturas y escrituras no serán llamadas al sistema.
Mike Spear
12

Quiere agregar puntos que puedan ser útiles.

ACERCA DE FILE *

  1. no se puede utilizar para la comunicación entre procesos (IPC).
  2. utilícelo cuando necesite E / S con búfer de propósito general (printf, frpintf, snprintf, scanf)
  3. Lo uso muchas veces para depurar registros. ejemplo,

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

ACERCA DE FILE DESCRIPTOR

  1. Generalmente se usa para IPC.

  2. Da control de bajo nivel a archivos en sistemas * nix (dispositivos, archivos, sockets, etc.), por lo que es más poderoso que el FILE *.

Akshay Patil
fuente
¿No puedes usar fdopen()para hacer cosas como IPC y dispositivos con FILE*?
osvein
De hecho, sí y no. No puede configurar e inicializar IPC con FILE*, pero puede crear un FILE*descriptor de archivo ( fdopen()) y luego cerrarlo FILEtambién cerrará el descriptor. Por lo tanto, puede hacer IPC, pero debe lidiar un poco con los descriptores de archivos para facilitar cualquier IPC directo.
Micah W
3

FILE *es más útil cuando se trabaja con archivos de texto y de usuario de entrada / salida, ya que permite el uso de funciones de la API como sprintf(), sscanf(), fgets(), feof()etc.

La API del descriptor de archivos es de bajo nivel, por lo que permite trabajar con sockets, tuberías, archivos mapeados en memoria (y archivos normales, por supuesto).

qrdl
fuente
1
+1 porque agregó archivos asignados en memoria, ya que a partir de mi lectura actual, las otras respuestas ya se han proporcionado.
ernie.cordell
3

Solo una nota para terminar la discusión (si está interesado) ....

fopenpuede ser inseguro, y probablemente debería usar fopen_so opencon bits exclusivos establecidos. C1X está ofreciendo xmodos, por lo que puede fopencon los modos "rx", "wx", etc.

Si usa open, podría considerar open(..., O_EXCL | O_RDONLY,... )o open(..., O_CREAT | O_EXCL | O_WRONLY,... ).

Consulte, por ejemplo, No haga suposiciones sobre fopen () y la creación de archivos .

jww
fuente
Como fopen_sno parece estar disponible con POSIX, supongo que el soultion más portátil sería open(2)y luego fdopen(2). (dejando las ventanas a un lado). Además, ¿qué sería más rápido fopen_s()o open(2)seguido fdopen(2)?
Mihir
1

Las llamadas al sistema utilizan principalmente descriptores de archivos, por ejemplo ready write. La función de biblioteca utilizará los punteros de archivo ( printf, scanf). Pero, las funciones de la biblioteca solo utilizan llamadas internas al sistema.

Pavunkumar
fuente
No estoy seguro de por qué está diciendo que las funciones de la biblioteca solo usan llamadas internas del sistema: si se refiere a las funciones estándar de CI / O (o cualquier otra para el caso), no estoy seguro de que eso sea (¿universalmente?) Cierto. De lo contrario, eso no es lo que dijiste, así que me gustaría que se limpiara un poco el lenguaje de tu publicación. La última frase me desconcierta.
ernie.cordell
1

Encontré un buen recurso aquí , que brinda una descripción general de alto nivel de las diferencias entre los dos:

Cuando desee hacer entrada o salida a un archivo, tiene la opción de dos mecanismos básicos para representar la conexión entre su programa y el archivo: descriptores de archivo y flujos. Los descriptores de archivo se representan como objetos de tipo int, mientras que los flujos se representan como objetos FILE *.

Los descriptores de archivo proporcionan una interfaz primitiva de bajo nivel para las operaciones de entrada y salida. Tanto los descriptores de archivos como los flujos pueden representar una conexión a un dispositivo (como un terminal), o una tubería o un enchufe para comunicarse con otro proceso, así como un archivo normal. Pero, si desea realizar operaciones de control que sean específicas de un tipo particular de dispositivo, debe usar un descriptor de archivo; no hay facilidades para usar streams de esta manera. También debe utilizar descriptores de archivo si su programa necesita realizar entrada o salida en modos especiales, como entrada sin bloqueo (o sondeo) (consulte las banderas de estado de archivo).

Los flujos proporcionan una interfaz de nivel superior, superpuesta a las funciones de descriptor de archivos primitivos. La interfaz de transmisión trata todo tipo de archivos de manera muy similar, con la única excepción de los tres estilos de almacenamiento en búfer que puede elegir (consulte Almacenamiento en búfer de transmisión).

La principal ventaja de usar la interfaz de flujo es que el conjunto de funciones para realizar operaciones de entrada y salida reales (a diferencia de las operaciones de control) en los flujos es mucho más rico y más poderoso que las funciones correspondientes para descriptores de archivos. La interfaz de descriptor de archivos proporciona solo funciones simples para transferir bloques de caracteres, pero la interfaz de flujo también proporciona potentes funciones de entrada y salida formateadas (printf y scanf), así como funciones para entrada y salida orientadas a caracteres y líneas.

Dado que los flujos se implementan en términos de descriptores de archivo, puede extraer el descriptor de archivo de un flujo y realizar operaciones de bajo nivel directamente en el descriptor de archivo. También puede abrir inicialmente una conexión como un descriptor de archivo y luego hacer una secuencia asociada con ese descriptor de archivo.

En general, debe seguir usando secuencias en lugar de descriptores de archivo, a menos que desee realizar alguna operación específica que solo se pueda realizar en un descriptor de archivo. Si es un programador principiante y no está seguro de qué funciones utilizar, le sugerimos que se concentre en las funciones de entrada formateadas (consulte Entrada formateada) y las funciones de salida formateada (consulte Salida formateada).

Si le preocupa la portabilidad de sus programas a sistemas distintos de GNU, también debe tener en cuenta que los descriptores de archivos no son tan portátiles como los flujos. Puede esperar que cualquier sistema que ejecute ISO C admita transmisiones, pero los sistemas que no son GNU pueden no admitir descriptores de archivo en absoluto, o pueden implementar solo un subconjunto de las funciones GNU que operan en descriptores de archivo. Sin embargo, la mayoría de las funciones de descriptor de archivos de la biblioteca GNU C están incluidas en el estándar POSIX.1.

Suraj Jain
fuente