logo

Apeluri de sistem de intrare-ieșire în C | Creați, deschideți, închideți, citiți, scrieți

Apelurile de sistem sunt apelurile pe care un program le face către nucleul sistemului pentru a furniza serviciile la care programul nu are acces direct. De exemplu, oferind acces la dispozitivele de intrare și ieșire, cum ar fi monitoare și tastaturi. Putem folosi diverse funcții furnizate în limbajul de programare C pentru apeluri de sistem de intrare/ieșire, cum ar fi crearea, deschiderea, citirea, scrierea etc.

Înainte de a trece la Apelurile de sistem I/O, trebuie să știm despre câțiva termeni importanți.



Terminologie importantă

Ce este descriptorul de fișier?

Descriptorul de fișier este un număr întreg care identifică în mod unic un fișier deschis al procesului.

Tabel Descriptor de fișier: Un fișier tabelul de descriptori este o colecție de indici de matrice întregi care sunt descriptori de fișiere în care elementele sunt pointeri către intrările tabelului de fișiere. Un tabel unic de descriptori de fișiere este furnizat în sistemul de operare pentru fiecare proces.



Intrare în tabelul fișierului: Intrările din tabelul de fișiere sunt o structură surogat în memorie pentru un fișier deschis, care este creată la procesarea unei cereri de deschidere a fișierului și aceste intrări mențin poziția fișierului.

Tabelul de fișiere intrare în C

Descriptori de fișiere standard : Când începe orice proces, atunci tabelul de descriptori a fișierului de proces fd(descriptor de fișier) 0, 1, 2 se deschide automat, (în mod implicit) fiecare dintre aceste 3 fd face referire la intrarea tabelului de fișiere pentru un fișier numit /dev/tty



/dev/tty : surogat în memorie pentru terminal.

Terminal : Combinație tastatură/ecran video.

Descriptori de fișiere standard

Citiți din stdin => citiți din fd 0 : Ori de câte ori scriem orice caracter de la tastatură, acesta citește de la stdin până la fd 0 și salvează într-un fișier numit /dev/tty.
Scrieți în stdout => scrieți în fd 1 : Ori de câte ori vedem orice ieșire pe ecranul video, aceasta este din fișierul numit /dev/tty și scrisă în stdout în ecran prin fd 1.
Scrieți în stderr => scrieți în fd 2 : Vedem orice eroare pe ecranul video, este și din acel fișier scrieți în stderr în ecran prin fd 2.

Apeluri de sistem de intrare/ieșire

Practic, există în total 5 tipuri de apeluri de sistem I/O:

1. C creați

Funcția create() este folosită pentru a crea un nou fișier gol în C. Putem specifica permisiunea și numele fișierului pe care dorim să-l creăm folosind funcția create(). Este definit în interior fișierul antet și steagurile care sunt transmise ca argumente sunt definite în interior fișier antet.

Sintaxa create() în C

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

Parametru

  • nume de fișier: numele fișierului pe care doriți să-l creați
  • modul: indică permisiunile noului fișier.

Valoare returnată

  • returnează primul descriptor de fișier neutilizat (în general 3 la prima creare a utilizării în proces, deoarece 0, 1, 2 fd sunt rezervate)
  • returnează -1 când o eroare

Cum funcționează C create() în sistemul de operare

  • Creați un nou fișier gol pe disc.
  • Creați o intrare în tabelul de fișiere.
  • Setați primul descriptor de fișier neutilizat pentru a indica intrarea în tabelul de fișiere.
  • Returnează descriptorul de fișier folosit, -1 la eșec.

2. C deschis

Funcția open() din C este folosită pentru a deschide fișierul pentru citire, scriere sau ambele. De asemenea, este capabil să creeze fișierul dacă acesta nu există. Este definit în interior fișierul antet și steagurile care sunt transmise ca argumente sunt definite în interior fișier antet.

Sintaxa lui open() în C

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

Parametrii

  • Cale: Calea către fișierul pe care vrem să-l deschidem.
    • Folosește cale absolută începând cu / când ești nu lucrând în același director ca fișier sursă C.
    • Utilizare cale relativă care este doar numele fișierului cu extensie, atunci când sunteți lucrând în același director ca fișier sursă C.
  • steaguri: Este folosit pentru a specifica modul în care doriți să deschideți fișierul. Putem folosi următoarele steaguri.

Steaguri

Descriere

O_RDONLY Deschide fișierul în modul numai citire.
O_NEGRESIT Deschide fișierul în modul numai de scriere.
O_RDWR Deschide fișierul în modul citire și scriere.
O_CREAT Creați un fișier dacă nu există.
O_EXCL Preveniți crearea dacă există deja.
O_ ANEXA Deschide fișierul și plasează cursorul la sfârșitul conținutului.
O_ASYNC Activați controlul intrării și ieșirii prin semnal.
O_CLOEXEC Activați modul close-on-exec pe fișierul deschis.
O_NONBLOCK Dezactivează blocarea fișierului deschis.
O_TMPFILE Creați un fișier temporar fără nume pe calea specificată.

Cum funcționează C open() în sistemul de operare

  • Găsiți fișierul existent pe disc.
  • Creați o intrare în tabelul de fișiere.
  • Setați primul descriptor de fișier neutilizat pentru a indica intrarea în tabelul de fișiere.
  • Returnează descriptorul de fișier folosit, -1 la eșec.

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

>

>

Ieșire

fd = 3>

3. C aproape

Funcția close() din C spune sistemului de operare că ați terminat cu un descriptor de fișier și închide fișierul indicat de descriptorul de fișier. Este definit în interior fișier antet.

teoria arborilor și grafurilor

Sintaxa close() în C

int close(int fd);>

Parametru

  • fd: F descriptor de fișier al fișierului pe care doriți să-l închideți.

Valoare returnată

  • 0 asupra succesului.
  • -1 pe eroare.

Cum funcționează C close() în sistemul de operare

  • Distrugeți intrarea din tabelul de fișiere la care se face referire de elementul fd din tabelul descriptor de fișiere
    – Atâta timp cât niciun alt proces nu indică acest lucru!
  • Setați elementul fd din tabelul descriptor al fișierului la NUL

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

>

>

Ieșire

opened the fd = 3 closed the fd.>

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

>

>

Ieșire

fd2 = 3>

Aici, în acest cod se întoarce mai întâi open() 3 deoarece atunci când procesul principal este creat, atunci fd 0, 1, 2 sunt deja luate de stdin , stdout, și stderr . Deci primul descriptor de fișier neutilizat este 3 în tabelul descriptor al fișierului. După aceea, apelul de sistem close() este liber 3 descriptori de fișiere și apoi setați 3 descriptori de fișiere ca nul . Deci, când am apelat al doilea open(), atunci primul fd neutilizat este și el 3 . Deci, rezultatul acestui program este 3 .

4. C citit

Din fișierul indicat de descriptorul de fișier fd, funcția read() citește cantitatea specificată de octeți cnt de intrare în zona de memorie indicată de buf . Un read() cu succes actualizează timpul de acces pentru fișier. Funcția read() este definită și în interiorul fișierului antet.

Sintaxa read() în C

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

Parametrii

  • fd: descriptor de fișier al fișierului din care urmează să fie citite datele.
  • buf: tampon din care să citească datele
  • cnt: lungimea tamponului

Valoare returnată

  • return Numărul de octeți citiți la succes
  • returnați 0 când ajungeți la sfârșitul fișierului
  • returnează -1 la eroare
  • returnează -1 la întreruperea semnalului

Puncte importante

  • buf trebuie să indice o locație de memorie validă cu o lungime nu mai mică decât dimensiunea specificată din cauza depășirii.
  • fd ar trebui să fie un descriptor de fișier valid returnat de la open() pentru a efectua operația de citire, deoarece dacă fd este NULL, citirea ar trebui să genereze o eroare.
  • cnt este numărul solicitat de octeți citiți, în timp ce valoarea returnată este numărul real de octeți citiți. De asemenea, uneori, citirea apelului de sistem ar trebui să citească mai puțini octeți decât cnt.

Exemplu de read() în 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;> }>

>

>

Ieșire

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

Să presupunem că foobar.txt este format din cele 6 caractere ASCII foobar. Atunci care este rezultatul următorului program?

C


cadru de primăvară



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

>

>

java convertește char în int

Ieșire

c = f>

Descriptorii fd1 și fd2 fiecare are propria sa intrare în tabelul de fișiere deschise, astfel încât fiecare descriptor are propria poziție a fișierului pentru foobar.txt . Astfel, cititul din fd2 citește primul octet al foobar.txt , iar rezultatul este c = f , nu c = o .

5. C scrie

Scrie cnt octeți din buf în fișierul sau socketul asociat cu fd. cnt nu trebuie să fie mai mare decât INT_MAX (definit în fișierul antet limits.h). Dacă cnt este zero, write() returnează pur și simplu 0 fără a încerca nicio altă acțiune.

Scrie () este, de asemenea, definit în interior fișier antet.

Sintaxa scrierii () în C

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

Parametrii

  • fd: descriptor de fișier
  • buf: tampon din care să scrieți datele.
  • cnt: lungimea tamponului.

Valoare returnată

  • returnează numărul de octeți scriși la succes.
  • returnați 0 când ajungeți la sfârșitul fișierului.
  • returnează -1 la eroare.
  • returnează -1 la întreruperile semnalului.

Puncte importante despre C scrie

  • Fișierul trebuie deschis pentru operațiuni de scriere
  • buf trebuie să fie cel puțin atât de lungă cât este specificat de cnt, deoarece dacă dimensiunea buf este mai mică decât cnt, atunci buf va duce la starea de depășire.
  • cnt este numărul solicitat de octeți de scris, în timp ce valoarea returnată este numărul real de octeți scriși. Acest lucru se întâmplă când fd are un număr mai mic de octeți de scris decât cnt.
  • Dacă write() este întrerupt de un semnal, efectul este unul dintre următoarele:
    • Dacă write() nu a scris încă nicio dată, returnează -1 și setează errno la EINTR.
    • Dacă write() a scris cu succes unele date, returnează numărul de octeți pe care i-a scris înainte de a fi întrerupt.

Exemplu de write() în 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);> }>

>

>

Ieșire

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

Aici, când vedeți în fișierul foo.txt după rularea codului, obțineți un salut tocilari . Dacă fișierul foo.txt are deja conținut în el, atunci scrierea unui apel de sistem suprascrie conținutul și tot conținutul anterior este șters si doar salut tocilari continutul va avea in fisier.

Exemplu: Imprimați hello world din program fără a utiliza nicio funcție 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;> }>

>

>

Ieșire

hello world>

În acest cod, șirul matricei buf1 Salut Lume este mai întâi scris în stdin fd[0] apoi după aceea acest șir scrie în stdin în matricea buf2. După aceea, scrieți în matricea buf2 în stdout și imprimați ieșirea Salut Lume .