logo

Llamadas al sistema de entrada-salida en C | Crear, abrir, cerrar, leer, escribir

Las llamadas al sistema son las llamadas que realiza un programa al núcleo del sistema para proporcionar los servicios a los que el programa no tiene acceso directo. Por ejemplo, proporcionar acceso a dispositivos de entrada y salida, como monitores y teclados. Podemos utilizar varias funciones proporcionadas en el lenguaje de programación C para llamadas al sistema de entrada/salida, como crear, abrir, leer, escribir, etc.

Antes de pasar a las llamadas al sistema de E/S, necesitamos conocer algunos términos importantes.

Terminología importante

¿Qué es el descriptor de archivo?



El descriptor de archivo es un número entero que identifica de forma única un archivo abierto del proceso.

Tabla de descriptores de archivos: un archivo La tabla de descriptores es la colección de índices de matriz de enteros que son descriptores de archivos en los que los elementos son punteros a las entradas de la tabla de archivos. En el sistema operativo se proporciona una tabla de descriptores de archivos única para cada proceso.

Entrada de tabla de archivos: Las entradas de la tabla de archivos son una estructura sustituta en memoria para un archivo abierto, que se crea al procesar una solicitud para abrir el archivo y estas entradas mantienen la posición del archivo.

Entrada de tabla de archivos en C

Descriptores de archivos estándar : Cuando se inicia cualquier proceso, el fd (descriptor de archivo) 0, 1, 2 de la tabla de descriptores de archivos de ese proceso se abre automáticamente (de forma predeterminada) cada una de estas 3 fd hace referencia a la entrada de la tabla de archivos para un archivo llamado /desarrollo/tty

/desarrollo/tty : sustituto en memoria del terminal.

Terminal : Combinación de teclado/pantalla de vídeo.

Descriptores de archivos estándar

Leer desde stdin => leer desde fd 0 : Cada vez que escribimos un carácter desde el teclado, se lee desde stdin hasta fd 0 y se guarda en un archivo llamado /dev/tty.
Escribir en stdout => escribir en fd 1 : Siempre que vemos alguna salida en la pantalla de video, es del archivo llamado /dev/tty y escrito en la salida estándar en la pantalla hasta fd 1.
Escribir en stderr => escribir en fd 2 : Vemos cualquier error en la pantalla de video, también es desde ese archivo que se escribe en stderr en la pantalla a través de fd 2.

Llamadas al sistema de entrada/salida

Básicamente, existen un total de 5 tipos de llamadas al sistema de E/S:

1. C crear

La función create() se usa para crear un nuevo archivo vacío en C. Podemos especificar el permiso y el nombre del archivo que queremos crear usando la función create(). esta definido por dentro archivo de encabezado y las banderas que se pasan como argumentos se definen dentro archivo de cabecera.

Sintaxis de crear() en C

int   create  (char *  filename  , mode_t   mode  );>

Parámetro

  • Nombre del archivo: nombre del archivo que desea crear
  • modo: indica los permisos del nuevo archivo.

Valor de retorno

  • devolver el primer descriptor de archivo no utilizado (generalmente 3 cuando se crea el uso por primera vez en el proceso porque 0, 1, 2 fd están reservados)
  • devolver -1 cuando hay un error

Cómo funciona C create() en el sistema operativo

  • Cree un nuevo archivo vacío en el disco.
  • Crear entrada de tabla de archivos.
  • Configure el primer descriptor de archivo no utilizado para que apunte a la entrada de la tabla de archivos.
  • Descriptor de archivo de retorno utilizado, -1 en caso de error.

2.C abierto

La función open() en C se utiliza para abrir el archivo para lectura, escritura o ambas cosas. También es capaz de crear el archivo si no existe. esta definido por dentro archivo de encabezado y las banderas que se pasan como argumentos se definen dentro archivo de cabecera.

Sintaxis de open() en C

int   open   (const char*   Path  , int   flags  );>

Parámetros

  • Camino: Ruta al archivo que queremos abrir.
    • Utilizar el camino absoluto comenzando con / cuando estás no trabajando en el mismo directorio como el archivo fuente C.
    • Usar camino relativo que es solo el nombre del archivo con extensión, cuando estás trabajando en el mismo directorio como el archivo fuente C.
  • banderas: Se utiliza para especificar cómo desea abrir el archivo. Podemos utilizar las siguientes banderas.

Banderas

Descripción

O_RDONLY Abre el archivo en modo de solo lectura.
O_WRONLY Abre el archivo en modo de solo escritura.
O_RDWR Abre el archivo en modo lectura y escritura.
O_CREAR Crea un archivo si no existe.
O_EXCL Impedir la creación si ya existe.
O_ ANEXAR Abre el archivo y coloca el cursor al final del contenido.
O_ASYNC Habilita el control de entrada y salida por señal.
O_CLOEXEC Habilite el modo de cierre en ejecución en el archivo abierto.
O_NONBLOCK Desactiva el bloqueo del archivo abierto.
O_TMPFILE Cree un archivo temporal sin nombre en la ruta especificada.

Cómo funciona C open() en el sistema operativo

  • Busque el archivo existente en el disco.
  • Crear entrada de tabla de archivos.
  • Configure el primer descriptor de archivo no utilizado para que apunte a la entrada de la tabla de archivos.
  • Descriptor de archivo de retorno utilizado, -1 en caso de error.

Ejemplo de C abierto()

C




// C program to illustrate> // open system call> #include> #include> #include> #include> extern> int> errno>;> int> main()> {> >// if file does not have in directory> >// then file foo.txt is created.> >int> fd = open(>'foo.txt'>, O_RDONLY | O_CREAT);> >printf>(>'fd = %d '>, fd);> >if> (fd == -1) {> >// print which type of error have in a code> >printf>(>'Error Number % d '>,>errno>);> >// print program detail 'Success or failure'> >perror>(>'Program'>);> >}> >return> 0;> }>

>

>

Producción

fd = 3>

3. C cerrar

La función close() en C le dice al sistema operativo que ha terminado con un descriptor de archivo y cierra el archivo señalado por el descriptor de archivo. esta definido por dentro archivo de cabecera.

Sintaxis de close() en C

int close(int fd);>

Parámetro

  • fd:F descriptor del archivo que desea cerrar.

Valor de retorno

  • 0 sobre el éxito.
  • -1 por error.

Cómo funciona C close() en el sistema operativo

  • Destruir la entrada de la tabla de archivos a la que hace referencia el elemento fd de la tabla de descriptores de archivos
    – ¡Siempre y cuando ningún otro proceso lo apunte!
  • Establezca el elemento fd de la tabla de descriptores de archivos en NULO

Ejemplo 1: cerrar() en C

C




// C program to illustrate close system Call> #include> #include> #include> int> main()> {> >int> fd1 = open(>'foo.txt'>, O_RDONLY);> >if> (fd1 <0) {> >perror>(>'c1'>);> >exit>(1);> >}> >printf>(>'opened the fd = % d '>, fd1);> >// Using close system Call> >if> (close(fd1) <0) {> >perror>(>'c1'>);> >exit>(1);> >}> >printf>(>'closed the fd. '>);> }>

>

>

Producción

opened the fd = 3 closed the fd.>

Ejemplo 2:

C


sistema operativo de red



// C program to illustrate close system Call> #include> #include> int> main()> {> >// assume that foo.txt is already created> >int> fd1 = open(>'foo.txt'>, O_RDONLY, 0);> >close(fd1);> > >// assume that baz.tzt is already created> >int> fd2 = open(>'baz.txt'>, O_RDONLY, 0);> > >printf>(>'fd2 = % d '>, fd2);> >exit>(0);> }>

>

>

Producción

fd2 = 3>

Aquí, en este código, primero se devuelve open() 3 porque cuando se crea el proceso principal, entonces fd 0, 1, 2 ya están tomados por entrada estándar , salida estándar, y stderr . Entonces, el primer descriptor de archivo no utilizado es 3 en la tabla de descriptores de archivos. Después de eso, en close() la llamada al sistema es gratuita. 3 descriptores de archivos y luego configurar 3 descriptores de archivos como nulo . Entonces, cuando llamamos al segundo open(), el primer fd no utilizado también es 3 . Entonces, el resultado de este programa es 3 .

4. C leer

Del archivo indicado por el descriptor de archivo fd, la función read() lee la cantidad especificada de bytes cnt de entrada en el área de memoria indicada por buf . Una lectura exitosa() actualiza el tiempo de acceso al archivo. La función read() también se define dentro del archivo de encabezado.

Sintaxis de lectura() en C

size_t   read   (int   fd  , void*   buf  , size_t   cnt  );>

Parámetros

  • fd: descriptor de archivo del archivo desde el cual se leerán los datos.
  • buf: buffer para leer datos de
  • ct: longitud del buffer

Valor de retorno

  • devolver Número de bytes leídos en caso de éxito
  • devolver 0 al llegar al final del archivo
  • devolver -1 en caso de error
  • retorno -1 en interrupción de señal

Puntos importantes

  • buf necesita apuntar a una ubicación de memoria válida con una longitud no menor que el tamaño especificado debido al desbordamiento.
  • fd debe ser un descriptor de archivo válido devuelto desde open() para realizar la operación de lectura porque si fd es NULL entonces la lectura debería generar un error.
  • cnt es el número solicitado de bytes leídos, mientras que el valor de retorno es el número real de bytes leídos. Además, algunas veces la llamada al sistema de lectura debería leer menos bytes que cnt.

Ejemplo de lectura() en C

C




// C program to illustrate> // read system Call> #include> #include> #include> int> main()> {> >int> fd, sz;> >char>* c = (>char>*)>calloc>(100,>sizeof>(>char>));> >fd = open(>'foo.txt'>, O_RDONLY);> >if> (fd <0) {> >perror>(>'r1'>);> >exit>(1);> >}> >sz = read(fd, c, 10);> >printf>(>'called read(% d, c, 10). returned that'> >' %d bytes were read. '>,> >fd, sz);> >c[sz] =>' '>;> >printf>(>'Those bytes are as follows: % s '>, c);> >return> 0;> }>

>

>

Producción

called read(3, c, 10). returned that 10 bytes were read. Those bytes are as follows: 0 0 0 foo.>

Supongamos que foobar.txt consta de foobar de 6 caracteres ASCII. Entonces ¿cuál es el resultado del siguiente programa?

C




// C program to illustrate> // read system Call> #include> #include> #include> #include> int> main()> {> >char> c;> >int> fd1 = open(>'sample.txt'>, O_RDONLY, 0);> >int> fd2 = open(>'sample.txt'>, O_RDONLY, 0);> >read(fd1, &c, 1);> >read(fd2, &c, 1);> >printf>(>'c = %c '>, c);> >exit>(0);> }>

>

>

Producción

c = f>

Los descriptores fd1 y fd2 cada uno tiene su propia entrada en la tabla de archivos abiertos, por lo que cada descriptor tiene su propia posición de archivo para foobar.txt . Así, la lectura de fd2 lee el primer byte de foobar.txt , y la salida es c = f , no c = o .

5. C escribir

Escribe cnt bytes desde buf al archivo o socket asociado con fd. cnt no debe ser mayor que INT_MAX (definido en el archivo de encabezado limits.h). Si cnt es cero, write() simplemente devuelve 0 sin intentar ninguna otra acción.

La escritura() también está definida dentro archivo de cabecera.

Sintaxis de escribir() en C

size_t   write   (int   fd  , void*   buf  , size_t   cnt  );>

Parámetros

  • fd: descriptor de archivo
  • buf: buffer para escribir datos.
  • ct: longitud del buffer.

Valor de retorno

  • devuelve el número de bytes escritos en caso de éxito.
  • devuelve 0 al llegar al final del archivo.
  • devuelve -1 en caso de error.
  • devuelve -1 en caso de interrupciones de señal.

Puntos importantes sobre la escritura en C

  • El archivo debe abrirse para operaciones de escritura.
  • buf debe ser al menos tan largo como lo especifica cnt porque si el tamaño de buf es menor que cnt, entonces buf provocará la condición de desbordamiento.
  • cnt es el número solicitado de bytes para escribir, mientras que el valor de retorno es el número real de bytes escritos. Esto sucede cuando fd tiene menos bytes para escribir que cnt.
  • Si write() es interrumpido por una señal, el efecto es uno de los siguientes:
    • Si write() aún no ha escrito ningún dato, devuelve -1 y establece errno en EINTR.
    • Si write() ha escrito con éxito algunos datos, devuelve el número de bytes que escribió antes de ser interrumpido.

Ejemplo de escritura() en C

C




// C program to illustrate> // write system Call> #include> #include> main()> {> int> sz;> int> fd = open(>'foo.txt'>, O_WRONLY | O_CREAT | O_TRUNC, 0644);> if> (fd <0)> {> >perror>(>'r1'>);> >exit>(1);> }> sz = write(fd,>'hello geeks '>,>strlen>(>'hello geeks '>));> printf>(>'called write(% d, 'hello geeks ', %d).'> >' It returned %d '>, fd,>strlen>(>'hello geeks '>), sz);> close(fd);> }>

índice de cadena java de

>

>

Producción

called write(3, 'hello geeks
', 12). it returned 11>

Aquí, cuando ve el archivo foo.txt después de ejecutar el código, obtiene un hola frikis . Si el archivo foo.txt ya tiene contenido, las llamadas del sistema de escritura sobrescriben el contenido y todo el contenido anterior se elimina. eliminado y solo hola frikis contenido tendrá en el archivo.

Ejemplo: imprima hola mundo desde el programa sin utilizar ninguna función printf.

C




// C program to illustrate> // I/O system Calls> #include> #include> #include> #include> int> main(>void>)> {> >int> fd[2];> >char> buf1[12] =>'hello world'>;> >char> buf2[12];> >// assume foobar.txt is already created> >fd[0] = open(>'foobar.txt'>, O_RDWR);> >fd[1] = open(>'foobar.txt'>, O_RDWR);> >write(fd[0], buf1,>strlen>(buf1));> >write(1, buf2, read(fd[1], buf2, 12));> >close(fd[0]);> >close(fd[1]);> >return> 0;> }>

>

>

Producción

hello world>

En este código, la cadena de la matriz buf1 Hola Mundo se escribe primero en stdin fd[0] y luego esta cadena se escribe en stdin en la matriz buf2. Después de eso, escriba en la matriz buf2 en la salida estándar e imprima la salida. Hola Mundo .