Systeemaanroepen zijn de oproepen die een programma naar de systeemkernel doet om diensten te leveren waartoe het programma geen directe toegang heeft. Bijvoorbeeld het verlenen van toegang tot invoer- en uitvoerapparaten zoals monitoren en toetsenborden. We kunnen verschillende functies van de programmeertaal C gebruiken voor invoer-/uitvoersysteemaanroepen zoals creëren, openen, lezen, schrijven, enz.
Voordat we verder gaan met de I/O-systeemoproepen, moeten we een paar belangrijke termen kennen.
Belangrijke terminologie
Wat is de bestandsdescriptor?
De bestandsdescriptor is een geheel getal dat op unieke wijze een geopend bestand van het proces identificeert.
Bestandsdescriptortabel: een bestand descriptortabel is de verzameling integer-array-indices die bestandsdescriptors zijn waarin elementen verwijzingen zijn naar bestandstabelitems. Voor elk proces is er in het besturingssysteem één unieke tabel met bestandsbeschrijvingen aanwezig.
Bestandstabelinvoer: Bestandstabelitems zijn een structuur in het geheugensurrogaat voor een geopend bestand, dat wordt gemaakt bij het verwerken van een verzoek om het bestand te openen en deze items behouden de bestandspositie.

Standaard bestandsbeschrijvingen : Wanneer een proces start, wordt de fd (bestandsdescriptor) 0, 1, 2 van die procesbestandsdescriptorstabel automatisch geopend, (standaard) elk van deze 3 fd-verwijzingen naar de bestandstabelinvoer voor een bestand met de naam /dev/tty
/dev/tty : In-memory surrogaat voor de terminal.
Terminal : Combinatie toetsenbord/videoscherm.

Lezen vanaf stdin => lezen vanaf fd 0 : Telkens wanneer we een teken vanaf het toetsenbord schrijven, wordt het gelezen van stdin tot en met fd 0 en wordt het opgeslagen in een bestand met de naam /dev/tty.
Schrijven naar stdout => schrijven naar fd 1 : Telkens wanneer we enige uitvoer op het videoscherm zien, is deze afkomstig van het bestand met de naam /dev/tty en geschreven naar stdout in het scherm via fd 1.
Schrijven naar stderr => schrijven naar fd 2 : We zien elke fout op het videoscherm, deze komt ook van dat bestand en schrijft naar stderr in het scherm via fd 2.
Invoer-/uitvoersysteemoproepen
In principe zijn er in totaal 5 typen I/O-systeemaanroepen:
1. C creëren
De create() functie wordt gebruikt om een nieuw leeg bestand in C te maken. We kunnen de toestemming en de naam van het bestand dat we willen maken specificeren met behulp van de create() functie. Het is van binnen gedefinieerd header-bestand en de vlaggen die als argumenten worden doorgegeven, worden daarin gedefinieerd header-bestand.
Syntaxis van create() in C
int create (char * filename , mode_t mode );>
Parameter
- bestandsnaam: naam van het bestand dat u wilt maken
- modus: geeft de machtigingen van het nieuwe bestand aan.
Winstwaarde
- retourneer de eerste ongebruikte bestandsdescriptor (meestal 3 bij het eerste gebruik in het proces omdat 0, 1, 2 fd gereserveerd zijn)
- retourneer -1 bij een fout
Hoe C create() werkt in besturingssystemen
- Maak een nieuw leeg bestand op de schijf.
- Bestandstabelinvoer maken.
- Stel de eerste ongebruikte bestandsdescriptor zo in dat deze naar de bestandstabelinvoer verwijst.
- Retourbestandsdescriptor gebruikt, -1 bij falen.
2. C geopend
De functie open() in C wordt gebruikt om het bestand te openen voor lezen, schrijven of beide. Het is ook in staat om het bestand te maken als het niet bestaat. Het is van binnen gedefinieerd header-bestand en de vlaggen die als argumenten worden doorgegeven, worden daarin gedefinieerd header-bestand.
Syntaxis van open() in C
int open (const char* Path , int flags );>
Parameters
- Pad: Pad naar het bestand dat we willen openen.
- Gebruik de absoluut pad beginnend met / wanneer je bent niet in dezelfde map werken als het C-bronbestand.
- Gebruik relatief pad dat is alleen de bestandsnaam met extensie, als u dat bent in dezelfde map werken als het C-bronbestand.
- vlaggen: Het wordt gebruikt om aan te geven hoe u het bestand wilt openen. We kunnen de volgende vlaggen gebruiken.
| Vlaggen | Beschrijving |
|---|---|
| O_RDONLY | Opent het bestand in de alleen-lezenmodus. |
| O_FOUT | Opent het bestand in alleen-schrijven-modus. |
| O_RDWR | Opent het bestand in lees- en schrijfmodus. |
| O_CREËREN | Maak een bestand als het nog niet bestaat. |
| O_EXCL | Voorkom creatie als het al bestaat. |
| O_ APPEND | Opent het bestand en plaatst de cursor aan het einde van de inhoud. |
| O_ASYNC | Schakel invoer- en uitvoercontrole via signaal in. |
| O_CLOEXEC | Schakel de close-on-exec-modus in voor het geopende bestand. |
| O_NOBLOCK | Schakelt het blokkeren van het geopende bestand uit. |
| O_TMPFILE | Maak een naamloos tijdelijk bestand op het opgegeven pad. |
Hoe C open() werkt in besturingssystemen
- Zoek het bestaande bestand op de schijf.
- Bestandstabelinvoer maken.
- Stel de eerste ongebruikte bestandsdescriptor zo in dat deze naar de bestandstabelinvoer verwijst.
- Retourbestandsdescriptor gebruikt, -1 bij falen.
Voorbeeld van 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;> }> |
>
>
Uitvoer
fd = 3>
3. C sluiten
De close()-functie in C vertelt het besturingssysteem dat u klaar bent met een bestandsdescriptor en sluit het bestand waarnaar de bestandsdescriptor verwijst. Het is van binnen gedefinieerd header-bestand.
Syntaxis van close() in C
int close(int fd);>
Parameter
- fd: F ile-descriptor van het bestand dat u wilt sluiten.
Winstwaarde
- 0 op succes.
- -1 op fout.
Hoe C close() werkt in het besturingssysteem
- Vernietig de bestandstabelinvoer waarnaar wordt verwezen door element fd van de bestandsdescriptortabel
– Zolang geen enkel ander proces ernaar verwijst! - Stel element fd van de bestandsdescriptortabel in op NUL
Voorbeeld 1: close() in 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.
'>);> }> |
>
>
Uitvoer
opened the fd = 3 closed the fd.>
Voorbeeld 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);> }> |
>
>
Uitvoer
fd2 = 3>
Hier keert in deze code eerst open() terug 3 omdat wanneer het hoofdproces wordt gemaakt, fd 0, 1, 2 zijn al in beslag genomen stdin , stoer, En stderr . Dus de eerste ongebruikte bestandsdescriptor is 3 in de bestandsdescriptortabel. Daarna is de systeemaanroep in close() gratis 3 bestandsdescriptors en stel deze vervolgens in 3 bestandsbeschrijvingen als nul . Dus als we de tweede open() aanroepen, dan is de eerste ongebruikte fd dat ook 3 . De uitvoer van dit programma is dus 3 .
4. C lezen
Uit het bestand dat wordt aangegeven door de bestandsdescriptor fd, leest de functie read() het opgegeven aantal bytes cnt van invoer in het geheugengebied aangegeven door buf . Een succesvolle read() werkt de toegangstijd voor het bestand bij. De functie read() wordt ook gedefinieerd in het headerbestand.
Syntaxis van read() in C
size_t read (int fd , void* buf , size_t cnt );>
Parameters
- fd: bestandsdescriptor van het bestand waaruit gegevens moeten worden gelezen.
- buf: buffer waaruit gegevens kunnen worden gelezen
- cnt: lengte van de buffer
Winstwaarde
- return Aantal gelezen bytes bij succes
- retourneert 0 bij het bereiken van het einde van het bestand
- retourneert -1 bij een fout
- return -1 bij signaalonderbreking
Belangrijke punten
- buf moet vanwege overflow verwijzen naar een geldige geheugenlocatie met een lengte die niet kleiner is dan de opgegeven grootte.
- fd moet een geldige bestandsdescriptor zijn die wordt geretourneerd door open() om de leesbewerking uit te voeren, want als fd NULL is, zou het lezen een fout moeten genereren.
- cnt is het gevraagde aantal gelezen bytes, terwijl de retourwaarde het daadwerkelijke aantal gelezen bytes is. Soms zou de leessysteemoproep ook minder bytes moeten lezen dan cnt.
Voorbeeld van read() in 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;> }> |
>
>
Uitvoer
called read(3, c, 10). returned that 10 bytes were read. Those bytes are as follows: 0 0 0 foo.>
Stel dat foobar.txt bestaat uit de 6 ASCII-tekens foobar. Wat is dan de output van het volgende programma?
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);> }> |
>
beperkingen van elektronisch bankieren
>
Uitvoer
c = f>
De descriptoren fd1 En fd2 hebben elk hun eigen geopende bestandstabelinvoer, dus elke descriptor heeft zijn eigen bestandspositie foobar.txt . Dus het voorlezen van fd2 leest de eerste byte van foobar.txt , en de uitvoer is c = f , niet c = o .
5. C schrijven
Schrijft cnt-bytes van buf naar het bestand of de socket die is gekoppeld aan fd. cnt mag niet groter zijn dan INT_MAX (gedefinieerd in het headerbestand limites.h). Als cnt nul is, retourneert write() eenvoudigweg 0 zonder enige andere actie te ondernemen.
De write() wordt ook binnenin gedefinieerd header-bestand.
Syntaxis van write() in C
size_t write (int fd , void* buf , size_t cnt );>
Parameters
- fd: bestandsbeschrijving
- buf: buffer waaruit gegevens moeten worden geschreven.
- cnt: lengte van de buffer.
Winstwaarde
- retourneert het aantal bytes dat bij succes is geschreven.
- retourneert 0 bij het bereiken van het einde van het bestand.
- retourneer -1 bij een fout.
- return -1 bij signaalonderbrekingen.
Belangrijke punten over C-schrijven
- Het bestand moet worden geopend voor schrijfbewerkingen
- buf moet minstens zo lang zijn als gespecificeerd door cnt, want als de buf-grootte kleiner is dan de cnt, zal buf leiden tot de overflow-conditie.
- cnt is het gevraagde aantal te schrijven bytes, terwijl de retourwaarde het werkelijke aantal geschreven bytes is. Dit gebeurt wanneer fd heeft een kleiner aantal bytes om te schrijven dan cnt.
- Als write() wordt onderbroken door een signaal, is het effect een van de volgende:
- Als write() nog geen gegevens heeft geschreven, retourneert het -1 en wordt errno ingesteld op EINTR.
- Als write() met succes bepaalde gegevens heeft geschreven, retourneert het het aantal bytes dat het schreef voordat het werd onderbroken.
Voorbeeld van write() in 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);> }> |
>
>
Uitvoer
called write(3, 'hello geeks ', 12). it returned 11>
Als je hier in het bestand foo.txt ziet nadat je de code hebt uitgevoerd, krijg je een Hallo nerds . Als het bestand foo.txt al enige inhoud bevat, overschrijven de write a-systeemaanroepen de inhoud en wordt alle voorgaande inhoud verwijderd en alleen Hallo nerds inhoud in het bestand zal hebben.
Voorbeeld: Druk hallo wereld af vanuit het programma zonder een printf-functie te gebruiken.
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;> }> |
>
>
Uitvoer
hello world>
In deze code de string van buf1 array Hallo Wereld wordt eerst in stdin fd[0] geschreven en daarna wordt deze string in stdin naar buf2 array geschreven. Schrijf daarna in de buf2-array naar de stdout en druk de uitvoer af Hallo Wereld .