logo

Wywołania systemowe wejścia-wyjścia w C | Twórz, otwieraj, zamykaj, czytaj, zapisuj

Wywołania systemowe to wywołania wykonywane przez program do jądra systemu w celu zapewnienia usług, do których program nie ma bezpośredniego dostępu. Na przykład zapewnienie dostępu do urządzeń wejściowych i wyjściowych, takich jak monitory i klawiatury. Możemy używać różnych funkcji dostępnych w języku programowania C dla wywołań systemowych wejścia/wyjścia, takich jak tworzenie, otwieranie, odczytywanie, zapisywanie itp.

Zanim przejdziemy do wywołań systemowych we/wy, musimy poznać kilka ważnych terminów.



Ważna terminologia

Co to jest deskryptor pliku?

Deskryptor pliku jest liczbą całkowitą, która jednoznacznie identyfikuje otwarty plik procesu.

Tabela deskryptorów plików: plik tablica deskryptorów to zbiór indeksów tablicy liczb całkowitych, które są deskryptorami plików, w których elementy są wskaźnikami do wpisów tabeli plików. Dla każdego procesu w systemie operacyjnym dostępna jest jedna unikalna tabela deskryptorów plików.



Wpis w tabeli plików: Wpisy w tabeli plików to struktura znajdująca się w pamięci, zastępująca otwarty plik, tworzona podczas przetwarzania żądania otwarcia pliku, a wpisy te utrzymują pozycję pliku.

Wpis do tabeli plików w C

Standardowe deskryptory plików : Kiedy rozpoczyna się dowolny proces, tablica deskryptorów plików tego procesu fd(deskryptor pliku) 0, 1, 2 otwiera się automatycznie (domyślnie) każde z tych 3 fd odwołuje się do wpisu tabeli plików dla pliku o nazwie /dev/tty



/dev/tty : Surogat w pamięci terminala.

Terminal : Połączenie klawiatury i ekranu wideo.

Standardowe deskryptory plików

Czytaj ze stdin => czytaj z fd 0 : Ilekroć zapiszemy dowolny znak z klawiatury, odczytuje on ze standardowego wejścia do fd 0 i zapisuje do pliku o nazwie /dev/tty.
Zapisz na standardowe wyjście => napisz na fd 1 : Ilekroć widzimy jakiekolwiek wyjście na ekranie wideo, pochodzi ono z pliku o nazwie /dev/tty i jest zapisywane na standardowe wyjście na ekranie do fd 1.
Napisz do stderr => napisz do fd 2 : Widzimy jakiś błąd na ekranie wideo, jest to również zapis z tego pliku na stderr na ekranie do fd 2.

Wywołania systemowe wejścia/wyjścia

Zasadniczo istnieje pięć typów wywołań systemowych we/wy:

1. C utwórz

Funkcja create() służy do utworzenia nowego, pustego pliku w C. Za pomocą funkcji create() możemy określić uprawnienia i nazwę pliku, który chcemy utworzyć. Jest to określone wewnątrz plik nagłówkowy, a flagi przekazywane jako argumenty są zdefiniowane w środku plik nagłówkowy.

Składnia create() w C

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

Parametr

  • Nazwa pliku: nazwa pliku, który chcesz utworzyć
  • tryb: wskazuje uprawnienia nowego pliku.

Wartość zwracana

  • zwróć pierwszy nieużywany deskryptor pliku (zwykle 3 podczas pierwszego tworzenia użycia w procesie, ponieważ 0, 1, 2 fd są zarezerwowane)
  • zwróć -1, gdy wystąpi błąd

Jak C create() działa w systemie operacyjnym

  • Utwórz nowy pusty plik na dysku.
  • Utwórz wpis w tabeli plików.
  • Ustaw pierwszy nieużywany deskryptor pliku, aby wskazywał wpis tabeli plików.
  • Zwróć użyty deskryptor pliku, -1 w przypadku niepowodzenia.

2. C otwarte

Funkcja open() w C służy do otwierania pliku do odczytu, zapisu lub obu. Jest również w stanie utworzyć plik, jeśli nie istnieje. Jest to określone wewnątrz plik nagłówkowy, a flagi przekazywane jako argumenty są zdefiniowane w środku plik nagłówkowy.

Składnia open() w C

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

Parametry

  • Ścieżka: Ścieżka do pliku, który chcemy otworzyć.
    • Użyj absolutna ścieżka zaczynając od / kiedy jesteś nie pracując w tym samym katalogu jako plik źródłowy C.
    • Używać względna ścieżka dostępu która jest tylko nazwą pliku z rozszerzeniem, jeśli tak jest pracując w tym samym katalogu jako plik źródłowy C.
  • flagi: Służy do określenia sposobu otwarcia pliku. Możemy użyć następujących flag.

Flagi

kiedy wynaleziono pierwszy komputer

Opis

O_RDONLY Otwiera plik w trybie tylko do odczytu.
O_WRONLY Otwiera plik w trybie tylko do zapisu.
O_RDWR Otwiera plik w trybie odczytu i zapisu.
O_UTWÓRZ Utwórz plik, jeśli nie istnieje.
O_WYKŁ Zapobiegaj tworzeniu, jeśli już istnieje.
O_ DOŁĄCZ Otwiera plik i umieszcza kursor na końcu zawartości.
O_ASYNC Włącz sterowanie wejściem i wyjściem za pomocą sygnału.
O_CLOEXEC Włącz tryb zamykania przy wykonywaniu w otwartym pliku.
O_NONBLOKU Wyłącza blokowanie otwieranego pliku.
O_TMPFILE Utwórz nienazwany plik tymczasowy w określonej ścieżce.

Jak C open() działa w systemie operacyjnym

  • Znajdź istniejący plik na dysku.
  • Utwórz wpis w tabeli plików.
  • Ustaw pierwszy nieużywany deskryptor pliku, aby wskazywał wpis tabeli plików.
  • Zwróć użyty deskryptor pliku, -1 w przypadku niepowodzenia.

Przykład 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;> }>

>

>

Wyjście

fd = 3>

3. C zamknij

Funkcja close() w C informuje system operacyjny, że skończyłeś z deskryptorem pliku i zamyka plik wskazany przez deskryptor pliku. Jest to określone wewnątrz plik nagłówkowy.

Składnia funkcji close() w C

int close(int fd);>

Parametr

  • fd: F ile deskryptor pliku, który chcesz zamknąć.

Wartość zwracana

  • 0 na sukces.
  • -1 na błędzie.

Jak C Close() działa w systemie operacyjnym

  • Zniszcz wpis tabeli plików, do którego odwołuje się element fd tabeli deskryptorów plików
    – O ile żaden inny proces na to nie wskazuje!
  • Ustaw element fd tabeli deskryptorów plików na ZERO

Przykład 1: zamknij() w 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. '>);> }>

>

>

Wyjście

opened the fd = 3 closed the fd.>

Przykład 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);> }>

>

>

Wyjście

fd2 = 3>

Tutaj w tym kodzie najpierw zwracana jest metoda open(). 3 ponieważ kiedy tworzony jest proces główny, wówczas fd 0, 1, 2 są już zajęte stdin , standardowe wyjście, I stderr . Zatem pierwszym nieużywanym deskryptorem pliku jest 3 w tabeli deskryptorów plików. Następnie w funkcji Close() wywołanie systemowe jest wolne 3 deskryptory plików, a następnie ustaw 3 deskryptory plików jako zero . Kiedy więc wywołaliśmy drugą metodę open(), wówczas pierwsza nieużywana funkcja fd również zostanie wywołana 3 . Zatem wyjściem tego programu jest 3 .

4. C czytaj

Z pliku wskazanego przez deskryptor pliku fd funkcja read() odczytuje określoną ilość bajtów cnt danych wejściowych do obszaru pamięci wskazanego przez buf . Pomyślne read() aktualizuje czas dostępu do pliku. Funkcja read() jest również zdefiniowana w pliku nagłówkowym.

Składnia read() w C

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

Parametry

  • fd: deskryptor pliku, z którego mają zostać odczytane dane.
  • buf: bufor, z którego można odczytać dane
  • cnt: długość bufora

Wartość zwracana

  • return Liczba bajtów odczytanych w przypadku powodzenia
  • zwróć 0 po osiągnięciu końca pliku
  • zwróć -1 w przypadku błędu
  • zwróć -1 w przypadku przerwania sygnału

Ważne punkty

  • buf musi wskazywać prawidłową lokalizację pamięci o długości nie mniejszej niż określony rozmiar z powodu przepełnienia.
  • fd powinien być poprawnym deskryptorem pliku zwróconym przez open() w celu wykonania operacji odczytu, ponieważ jeśli fd ma wartość NULL, wówczas odczyt powinien wygenerować błąd.
  • cnt to żądana liczba odczytanych bajtów, a zwracana wartość to rzeczywista liczba odczytanych bajtów. Ponadto czasami funkcja systemowa read powinna odczytać mniej bajtów niż cnt.

Przykład read() w 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;> }>

>

>

Wyjście

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

Załóżmy, że foobar.txt składa się z 6 znaków ASCII foobar. Jaki jest zatem wynik poniższego programu?

C


lista połączona w Javie



Powiedziała Madhuri
// 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);> }>

>

>

Wyjście

c = f>

Deskryptory fd1 I fd2 każdy ma swój własny otwarty wpis w tabeli plików, więc każdy deskryptor ma własną pozycję w pliku foobar.txt . Zatem odczyt z fd2 czyta pierwszy bajt foobar.txt , a wyjście jest do = f , nie do = o .

5. Napisz C

Zapisuje cnt bajtów z buf do pliku lub gniazda powiązanego z fd. cnt nie powinno być większe niż INT_MAX (zdefiniowane w pliku nagłówkowym limity.h). Jeśli cnt wynosi zero, write() po prostu zwraca 0, nie podejmując żadnej innej akcji.

Funkcja write() jest również zdefiniowana wewnątrz plik nagłówkowy.

Składnia write() w C

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

Parametry

  • fd: deskryptor pliku
  • buf: bufor, z którego będą zapisywane dane.
  • cnt: długość bufora.

Wartość zwracana

  • zwraca liczbę bajtów zapisanych w przypadku powodzenia.
  • zwróć 0 po osiągnięciu końca pliku.
  • zwróć -1 w przypadku błędu.
  • zwraca -1 w przypadku przerwania sygnału.

Ważne uwagi dotyczące zapisu w języku C

  • Aby móc wykonać operacje zapisu, plik musi zostać otwarty
  • buf musi być co najmniej tak długi, jak określono w cnt, ponieważ jeśli rozmiar buf jest mniejszy niż cnt, wówczas buf doprowadzi do warunku przepełnienia.
  • cnt to żądana liczba bajtów do zapisania, natomiast wartość zwracana to rzeczywista liczba zapisanych bajtów. Dzieje się tak, gdy fd ma mniejszą liczbę bajtów do zapisania niż cnt.
  • Jeśli funkcja write() zostanie przerwana przez sygnał, efekt będzie jeden z poniższych:
    • Jeśli funkcja write() nie zapisała jeszcze żadnych danych, zwraca -1 i ustawia errno na EINTR.
    • Jeśli funkcja write() pomyślnie zapisała jakieś dane, zwraca liczbę bajtów, które zapisała przed przerwaniem.

Przykład write() w 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);> }>

>

>

Wyjście

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

Tutaj, gdy zobaczysz w pliku foo.txt po uruchomieniu kodu, otrzymasz cześć maniakom . Jeśli plik foo.txt zawiera już jakąś treść, wywołania systemowe write a nadpiszą tę zawartość, a cała poprzednia zawartość zostanie usunięte i tylko cześć maniakom zawartość będzie znajdować się w pliku.

Przykład: Wydrukuj hello world z programu bez użycia funkcji 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;> }>

>

>

Wyjście

hello world>

W tym kodzie ciąg znaków tablicy buf1 Witaj świecie jest najpierw zapisywany na stdin fd[0], a następnie ten ciąg znaków jest zapisywany na stdin do tablicy buf2. Następnie zapisz do tablicy buf2 na standardowe wyjście i wydrukuj Witaj świecie .