logo

Crides al sistema d'entrada-sortida en C | Crear, obrir, tancar, llegir, escriure

Les trucades al sistema són les trucades que fa un programa al nucli del sistema per proporcionar els serveis als quals el programa no té accés directe. Per exemple, proporcionar accés a dispositius d'entrada i sortida, com ara monitors i teclats. Podem utilitzar diverses funcions proporcionades al llenguatge de programació C per a trucades al sistema d'entrada/sortida com ara crear, obrir, llegir, escriure, etc.

Abans de passar a les trucades del sistema d'E/S, hem de conèixer alguns termes importants.



Terminologia important

Què és el descriptor de fitxers?

El descriptor de fitxer és un nombre enter que identifica de manera única un fitxer obert del procés.

Taula de descriptors de fitxers: un fitxer La taula de descriptors és la col·lecció d'índexs de matrius enters que són descriptors de fitxers en els quals els elements són punters a les entrades de la taula de fitxers. Es proporciona una taula única de descriptors de fitxers al sistema operatiu per a cada procés.



Entrada de la taula de fitxers: Les entrades de la taula de fitxers són una estructura de substitució en memòria d'un fitxer obert, que es crea quan es processa una sol·licitud per obrir el fitxer i aquestes entrades mantenen la posició del fitxer.

Entrada de la taula de fitxers en C

números per a l'alfabet

Descriptors de fitxer estàndard : Quan s'inicia qualsevol procés, la taula de descriptors de fitxers de procés fd(descriptor de fitxer) 0, 1, 2 s'obre automàticament (per defecte) cadascun d'aquests 3 fd fa referència a l'entrada de la taula de fitxers per a un fitxer anomenat /dev/tty



/dev/tty : substitut en memòria del terminal.

Terminal : Combinació de teclat/pantalla de vídeo.

Descriptors de fitxer estàndard

Llegir des de stdin => llegir des de fd 0 : Sempre que escrivim qualsevol caràcter des del teclat, es llegeix des de stdin fins a fd 0 i es desa en un fitxer anomenat /dev/tty.
Escriure a stdout => escriure a fd 1 : Sempre que veiem qualsevol sortida a la pantalla de vídeo, és del fitxer anomenat /dev/tty i escrit a stdout a la pantalla mitjançant fd 1.
Escriure a stderr => escriure a fd 2 : Veiem qualsevol error a la pantalla de vídeo, també és des d'aquest fitxer escriure a stderr a la pantalla a través de fd 2.

Trucades del sistema d'entrada/sortida

Bàsicament, hi ha un total de 5 tipus de trucades al sistema d'E/S:

1. C crear

La funció create() s'utilitza per crear un nou fitxer buit en C. Podem especificar el permís i el nom del fitxer que volem crear mitjançant la funció create(). Està definit per dins dins es defineixen el fitxer de capçalera i els indicadors que es passen com a arguments fitxer de capçalera.

Sintaxi de create() en C

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

Paràmetre

  • nom de l'arxiu: nom del fitxer que voleu crear
  • mode: indica els permisos del nou fitxer.

Valor de retorn

  • retorna el primer descriptor de fitxer no utilitzat (generalment 3 quan es crea l'ús per primera vegada en el procés perquè 0, 1, 2 fd estan reservats)
  • retorna -1 quan hi ha un error

Com funciona C create() al sistema operatiu

  • Creeu un nou fitxer buit al disc.
  • Crea una entrada de taula de fitxers.
  • Estableix el primer descriptor de fitxer no utilitzat perquè apunti a l'entrada de la taula de fitxers.
  • Descriptor de fitxer de retorn utilitzat, -1 en cas d'error.

2. C obert

La funció open() en C s'utilitza per obrir el fitxer per llegir, escriure o ambdues coses. També és capaç de crear el fitxer si no existeix. Està definit per dins dins es defineixen el fitxer de capçalera i els indicadors que es passen com a arguments fitxer de capçalera.

Sintaxi d'open() en C

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

Paràmetres

  • Camí: Camí del fitxer que volem obrir.
    • Utilitzar el camí absolut començant per / quan ets no treballant al mateix directori com a fitxer font C.
    • Ús camí relatiu que només és el nom del fitxer amb extensió, quan ho siguis treballant al mateix directori com a fitxer font C.
  • banderes: S'utilitza per especificar com voleu obrir el fitxer. Podem utilitzar les següents banderes.

Banderes

Descripció

O_RDONLY Obre el fitxer en mode només de lectura.
O_NEWRONLY Obre el fitxer en mode només d'escriptura.
O_RDWR Obre el fitxer en mode de lectura i escriptura.
O_CREAR Creeu un fitxer si no existeix.
O_EXCL Evitar la creació si ja existeix.
O_ ANNEX Obre el fitxer i col·loca el cursor al final del contingut.
O_ASYNC Habilita el control d'entrada i sortida per senyal.
O_CLOEXEC Activeu el mode de tancament a l'executiu al fitxer obert.
O_NOBLOCK Desactiva el bloqueig del fitxer obert.
O_TMPFILE Creeu un fitxer temporal sense nom al camí especificat.

Com funciona C open() al sistema operatiu

  • Cerqueu el fitxer existent al disc.
  • Crea una entrada de taula de fitxers.
  • Estableix el primer descriptor de fitxer no utilitzat perquè apunti a l'entrada de la taula de fitxers.
  • Descriptor de fitxer de retorn utilitzat, -1 en cas d'error.

Exemple de C open()

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;> }>

>

>

Sortida

fd = 3>

3. C tancar

La funció close() en C indica al sistema operatiu que heu acabat amb un descriptor de fitxer i tanca el fitxer apuntat pel descriptor de fitxer. Està definit per dins fitxer de capçalera.

Sintaxi de close() en C

int close(int fd);>

Paràmetre

  • fd: f descriptor de fitxer del fitxer que voleu tancar.

Valor de retorn

  • 0 sobre l'èxit.
  • -1 per error.

Com funciona C close() al sistema operatiu

  • Destrueix l'entrada de la taula de fitxers a la qual fa referència l'element fd de la taula descriptor de fitxers
    – Sempre que no hi hagi cap altre procés que ho apunti!
  • Estableix l'element fd de la taula descriptor de fitxers a NUL

Exemple 1: close() 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. '>);> }>

>

>

Sortida

opened the fd = 3 closed the fd.>

Exemple 2:

C




// 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);> }>

>

>

Sortida

fd2 = 3>

Aquí, en aquest codi, primer retorna open(). 3 perquè quan es crea el procés principal, llavors fd 0, 1, 2 ja estan agafats per stdin , stdout, i stderr . Per tant, el primer descriptor de fitxer no utilitzat és 3 a la taula de descriptors de fitxers. Després d'això, la crida al sistema close() és lliure 3 descriptors de fitxers i després establir-los 3 descriptors de fitxers com nul . Així, quan vam cridar el segon open(), el primer fd no utilitzat també ho és 3 . Per tant, la sortida d'aquest programa és 3 .

4. C llegir

Des del fitxer indicat pel descriptor de fitxer fd, la funció read() llegeix la quantitat especificada de bytes cnt d'entrada a l'àrea de memòria indicada per buf . Una lectura correcta () actualitza el temps d'accés al fitxer. La funció read() també es defineix dins del fitxer de capçalera.

Sintaxi de read() en C

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

Paràmetres

  • fd: descriptor de fitxer del fitxer des del qual s'han de llegir les dades.
  • buf: buffer per llegir dades
  • cnt: longitud del buffer

Valor de retorn

  • retorn Nombre de bytes llegits amb èxit
  • retorna 0 en arribar al final del fitxer
  • retorna -1 en cas d'error
  • retorn -1 a la interrupció del senyal

Punts importants

  • buf necessita apuntar a una ubicació de memòria vàlida amb una longitud no inferior a la mida especificada a causa del desbordament.
  • fd hauria de ser un descriptor de fitxer vàlid retornat per open() per dur a terme l'operació de lectura perquè si fd és NULL, la lectura hauria de generar un error.
  • cnt és el nombre sol·licitat de bytes llegits, mentre que el valor de retorn és el nombre real de bytes llegits. A més, algunes vegades la trucada de sistema de lectura hauria de llegir menys bytes que cnt.

Exemple de read() a 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;> }>

>

>

Sortida

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

Suposem que foobar.txt consta dels 6 caràcters ASCII foobar. Aleshores, quina és la sortida del següent 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);> }>

>

>

Sortida

c = f>

Els descriptors fd1 i fd2 cadascun té la seva pròpia entrada de taula de fitxers oberts, de manera que cada descriptor té la seva pròpia posició de fitxer per foobar.txt . Així, la lectura de fd2 llegeix el primer byte de foobar.txt , i la sortida és c = f , no c = o .

5. C escriure

Escriu cnt bytes de buf al fitxer o socket associat amb fd. cnt no hauria de ser superior a INT_MAX (definit al fitxer de capçalera limits.h). Si cnt és zero, write() simplement retorna 0 sense intentar cap altra acció.

El write() també es defineix dins fitxer de capçalera.

Sintaxi de write() en C

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

Paràmetres

  • fd: descriptor de fitxer
  • buf: buffer per escriure dades.
  • cnt: longitud del buffer.

Valor de retorn

  • retorna el nombre de bytes escrits en cas d'èxit.
  • retorneu 0 en arribar al final del fitxer.
  • retorna -1 en cas d'error.
  • retorn -1 a les interrupcions del senyal.

Punts importants sobre l'escriptura C

  • El fitxer s'ha d'obrir per a operacions d'escriptura
  • buf ha de ser almenys tan llarg com l'especifica cnt perquè si la mida del buf és menor que el cnt, buf donarà lloc a la condició de desbordament.
  • cnt és el nombre sol·licitat de bytes per escriure, mentre que el valor de retorn és el nombre real de bytes escrits. Això passa quan fd té un nombre menor de bytes per escriure que cnt.
  • Si write() s'interromp per un senyal, l'efecte és un dels següents:
    • Si write() encara no ha escrit cap dada, retorna -1 i estableix errno a EINTR.
    • Si write() ha escrit amb èxit algunes dades, retorna el nombre de bytes que va escriure abans que s'interrompés.

Exemple de write() 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);> }>

recursivitat java

>

>

Sortida

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

Aquí, quan veieu al fitxer foo.txt després d'executar el codi, obteniu un hola geeks . Si el fitxer foo.txt ja té contingut, llavors les trucades d'escriptura d'un sistema sobreescriuran el contingut i tot el contingut anterior serà esborrat i només hola geeks contingut tindrà al fitxer.

Exemple: imprimiu hello world des del programa sense utilitzar cap funció 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;> }>

>

>

Sortida

hello world>

En aquest codi, la cadena de la matriu buf1 Hola món s'escriu primer a stdin fd[0] i després aquesta cadena escriu a stdin a la matriu buf2. Després d'això, escriviu a la matriu buf2 al stdout i imprimiu la sortida Hola món .