logo

Vhodno-izhodni sistemski klici v C | Ustvari, odpri, zapri, preberi, piši

Sistemski klici so klici, ki jih program naredi sistemskemu jedru, da zagotovi storitve, do katerih program nima neposrednega dostopa. Na primer zagotavljanje dostopa do vhodnih in izhodnih naprav, kot so monitorji in tipkovnice. Za vhodno/izhodne sistemske klice, kot so ustvarjanje, odpiranje, branje, pisanje itd., lahko uporabimo različne funkcije, ki so na voljo v programskem jeziku C.

Preden preidemo na V/I sistemske klice, moramo poznati nekaj pomembnih izrazov.



Pomembna terminologija

Kaj je deskriptor datoteke?

Deskriptor datoteke je celo število, ki enolično identificira odprto datoteko procesa.

Tabela deskriptorjev datoteke: datoteka tabela deskriptorjev je zbirka indeksov nizov celih števil, ki so deskriptorji datotek, v katerih so elementi kazalci na vnose tabele datotek. V operacijskem sistemu je za vsak proces na voljo ena edinstvena tabela deskriptorjev datotek.



Vnos tabele datotek: Vnosi tabele datotek so nadomestek strukture v pomnilniku za odprto datoteko, ki se ustvari pri obdelavi zahteve za odpiranje datoteke in ti vnosi ohranjajo položaj datoteke.

Vnos tabele datotek v C

Standardni deskriptorji datotek : Ko se kateri koli proces zažene, se fd (deskriptor datoteke) 0, 1, 2 tabele z deskriptorji datoteke tega procesa samodejno odpre (privzeto) vsaka od teh 3 fd referenc vnos tabele datotek za datoteko z imenom /dev/tty



/dev/tty : Nadomestek v pomnilniku za terminal.

Terminal : Kombinirana tipkovnica/video zaslon.

Standardni deskriptorji datotek

Branje iz stdin => branje iz fd 0 : Kadar koli napišemo kateri koli znak s tipkovnice, se bere od stdin do fd 0 in shrani v datoteko z imenom /dev/tty.
Pišite v stdout => pišite v fd 1 : Kadarkoli vidimo kakršen koli izhod na video zaslon, je iz datoteke z imenom /dev/tty in zapisan v stdout na zaslonu prek fd 1.
Pišite v stderr => pišite v fd 2 : Vidimo kakršno koli napako na video zaslonu, prav tako je iz te datoteke pisanje v stderr na zaslonu prek fd 2.

Vhodno/izhodni sistemski klici

V bistvu obstaja skupno 5 vrst V/I sistemskih klicev:

1. C ustvari

Funkcija create() se uporablja za ustvarjanje nove prazne datoteke v C. S funkcijo create() lahko določimo dovoljenje in ime datoteke, ki jo želimo ustvariti. Določeno je znotraj glava datoteke in zastavice, ki so posredovane kot argumenti, so definirane znotraj naslovna datoteka.

Sintaksa create() v C

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

Parameter

  • Ime datoteke: ime datoteke, ki jo želite ustvariti
  • način: označuje dovoljenja za novo datoteko.

Povratna vrednost

  • vrni prvi neuporabljen deskriptor datoteke (običajno 3 pri prvi uporabi v procesu, ker so 0, 1, 2 fd rezervirani)
  • vrni -1 ob napaki

Kako C create() deluje v OS

  • Na disku ustvarite novo prazno datoteko.
  • Ustvari vnos tabele datotek.
  • Nastavite prvi neuporabljeni deskriptor datoteke, da kaže na vnos tabele datotek.
  • Uporabljen deskriptor povratne datoteke, -1 ob napaki.

2. C odprto

Funkcija open() v C se uporablja za odpiranje datoteke za branje, pisanje ali oboje. Prav tako lahko ustvari datoteko, če ne obstaja. Določeno je znotraj glava datoteke in zastavice, ki so posredovane kot argumenti, so definirane znotraj naslovna datoteka.

Sintaksa open() v C

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

Parametri

  • Pot: Pot do datoteke, ki jo želimo odpreti.
    • Uporabi absolutna pot začenši z / ko ste ne delajo v istem imeniku kot izvorno datoteko C.
    • Uporaba relativna pot ki je samo ime datoteke s pripono, ko ste delajo v istem imeniku kot izvorno datoteko C.
  • zastave: Uporablja se za določitev, kako želite odpreti datoteko. Uporabimo lahko naslednje zastavice.

Zastave

Opis

SAMO O_RD Odpre datoteko v načinu samo za branje.
O_NAROBE Odpre datoteko v načinu samo za pisanje.
O_RDWR Odpre datoteko v načinu branja in pisanja.
O_USTVARI Ustvarite datoteko, če ne obstaja.
O_EXCL Preprečite ustvarjanje, če že obstaja.
O_ PRIPODAJ Odpre datoteko in postavi kazalec na konec vsebine.
O_ASYNC Omogoči nadzor vhoda in izhoda s signalom.
O_CLOEXEC Omogoči način zaprtja pri izvajanju odprte datoteke.
O_NONBLOCK Onemogoči blokiranje odprte datoteke.
O_TMPFILE Na podani poti ustvarite neimenovano začasno datoteko.

Kako C open() deluje v OS

  • Poiščite obstoječo datoteko na disku.
  • Ustvari vnos tabele datotek.
  • Nastavite prvi neuporabljeni deskriptor datoteke, da kaže na vnos tabele datotek.
  • Uporabljen deskriptor povratne datoteke, -1 ob napaki.

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

>

>

Izhod

fd = 3>

3. C zapri

Funkcija close() v C sporoči operacijskemu sistemu, da ste končali z deskriptorjem datoteke, in zapre datoteko, na katero kaže deskriptor datoteke. Določeno je znotraj naslovna datoteka.

Sintaksa close() v C

int close(int fd);>

Parameter

  • fd: F ile deskriptor datoteke, ki jo želite zapreti.

Povratna vrednost

  • 0 na uspeh.
  • -1 na napako.

Kako C close() deluje v OS

  • Uniči vnos tabele datotek, na katerega se sklicuje element fd tabele deskriptorjev datoteke
    – Dokler noben drug proces ne kaže na to!
  • Nastavite element fd tabele deskriptorjev datoteke na NIČ

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

>

>

Izhod

opened the fd = 3 closed the fd.>

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

>

statična funkcija v Javi

>

Izhod

fd2 = 3>

Tukaj se v tej kodi vrne first open(). 3 ker ko je ustvarjen glavni proces, potem fd 0, 1, 2 so že zasedli stdin , stdout, in stderr . Torej je prvi neuporabljen deskriptor datoteke 3 v tabeli deskriptorjev datoteke. Po tem v sistemskem klicu close() je ta prosta 3 deskriptorje datotek in nato nastavite 3 deskriptorji datotek kot nič . Torej, ko smo poklicali drugi open(), je tudi prvi neuporabljen fd 3 . Torej, rezultat tega programa je 3 .

4. C preberi

Iz datoteke, označene z deskriptorjem datoteke fd, funkcija read() prebere določeno količino bajtov cnt vnosa v pomnilniško območje, označeno z buf . Uspešen read() posodobi čas dostopa do datoteke. Funkcija read() je prav tako definirana znotraj datoteke glave.

Sintaksa read() v C

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

Parametri

  • fd: datotečni deskriptor datoteke, iz katere je treba prebrati podatke.
  • buf: medpomnilnik za branje podatkov
  • cnt: dolžina medpomnilnika

Povratna vrednost

  • return Število bajtov, prebranih ob uspehu
  • vrne 0, ko doseže konec datoteke
  • vrni -1 ob napaki
  • vrni -1 ob prekinitvi signala

Pomembne točke

  • buf zaradi prelivanja mora kazati na veljavno pomnilniško lokacijo z dolžino, ki ni manjša od navedene velikosti.
  • fd mora biti veljaven deskriptor datoteke, vrnjen iz open() za izvedbo operacije branja, ker če je fd NULL, mora branje ustvariti napako.
  • cnt je zahtevano število prebranih bajtov, medtem ko je vrnjena vrednost dejansko število prebranih bajtov. Prav tako mora sistemski klic read včasih prebrati manj bajtov kot cnt.

Primer read() v 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;> }>

>

>

Izhod

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

Recimo, da je foobar.txt sestavljen iz 6 znakov ASCII foobar. Kaj je potem rezultat naslednjega 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);> }>

>

>

Izhod

c = f>

Deskriptorji fd1 in fd2 vsak ima svoj vnos v tabeli odprtih datotek, tako da ima vsak deskriptor svoj položaj datoteke za foobar.txt . Tako je branje iz fd2 prebere prvi bajt od foobar.txt , izhod pa je c = f , ne c = o .

5. C pisati

Zapiše cnt bajtov iz buf v datoteko ali vtičnico, povezano s fd. cnt ne sme biti večji od INT_MAX (definirano v datoteki glave limits.h). Če je cnt enak nič, write() preprosto vrne 0, ne da bi poskušal izvesti kakršno koli drugo dejanje.

Write() je prav tako definiran znotraj naslovna datoteka.

Sintaksa write() v C

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

Parametri

  • fd: deskriptor datoteke
  • buf: medpomnilnik za pisanje podatkov.
  • cnt: dolžina medpomnilnika.

Povratna vrednost

  • ob uspehu vrne število zapisanih bajtov.
  • vrne 0, ko doseže konec datoteke.
  • vrni -1 ob napaki.
  • vrni -1 ob prekinitvi signala.

Pomembne točke o C write

  • Datoteko je treba odpreti za operacije pisanja
  • buf mora biti vsaj tako dolg, kot ga določa cnt, ker če je velikost buf manjša od cnt, bo buf povzročil stanje prelivanja.
  • cnt je zahtevano število bajtov za pisanje, medtem ko je vrnjena vrednost dejansko število zapisanih bajtov. To se zgodi, ko fd ima manjše število bajtov za pisanje kot cnt.
  • Če je write() prekinjen s signalom, je učinek eden od naslednjih:
    • Če write() še ni zapisal nobenih podatkov, vrne -1 in nastavi errno na EINTR.
    • Če je write() uspešno zapisal nekaj podatkov, vrne število bajtov, ki jih je zapisal, preden je bil prekinjen.

Primer write() v 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);> }>

izboljšana for loop java

>

>

Izhod

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

Tukaj, ko vidite v datoteki foo.txt po zagonu kode, dobite pozdravljeni geeki . Če je v datoteki foo.txt že nekaj vsebine, sistemski klici write a prepišejo vsebino in vsa prejšnja vsebina je izbrisano in samo pozdravljeni geeki vsebina bo imela v datoteki.

Primer: Natisnite hello world iz programa brez uporabe funkcije 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;> }>

>

>

Izhod

hello world>

V tej kodi je niz matrike buf1 Pozdravljen, svet se najprej zapiše v stdin fd[0], nato pa se ta niz zapiše v stdin v matriko buf2. Po tem zapišite v matriko buf2 v stdout in natisnite izhod Pozdravljen, svet .