logo

Системні виклики введення-виведення в C | Створювати, відкривати, закривати, читати, писати

Системні виклики — це виклики, які програма здійснює до системного ядра, щоб надати служби, до яких програма не має прямого доступу. Наприклад, надання доступу до пристроїв введення та виведення, таких як монітори та клавіатури. Ми можемо використовувати різні функції, надані мовою програмування C, для системних викликів введення/виведення, таких як створення, відкриття, читання, запис тощо.

Перш ніж перейти до системних викликів вводу-виводу, нам потрібно знати кілька важливих термінів.



Важлива термінологія

Що таке файловий дескриптор?

Дескриптор файлу — це ціле число, яке однозначно ідентифікує відкритий файл процесу.

Таблиця дескрипторів файлів: файл таблиця дескрипторів — це набір індексів масиву цілих чисел, які є дескрипторами файлів, у яких елементи є покажчиками на записи таблиці файлів. Для кожного процесу в операційній системі надається одна унікальна таблиця дескрипторів файлів.



Запис у таблиці файлів: Записи таблиці файлів — це структурний сурогат відкритого файлу в пам’яті, який створюється під час обробки запиту на відкриття файлу, і ці записи зберігають позицію файлу.

Запис таблиці файлів у C

Стандартні файлові дескриптори : Коли запускається будь-який процес, fd (дескриптор файлу) 0, 1, 2 таблиці дескрипторів файлів цього процесу відкривається автоматично (за замовчуванням) кожен із цих 3 fd посилається на запис таблиці файлів для файлу з назвою /dev/tty



/dev/tty : Сурогат терміналу в пам'яті.

Термінал : комбінована клавіатура/відеоекран.

Стандартні файлові дескриптори

Читання з stdin => читання з fd 0 : Щоразу, коли ми пишемо будь-який символ з клавіатури, він читає від stdin до fd 0 і зберігає у файлі з назвою /dev/tty.
Запис у стандартний вихід => запис у fd 1 : Щоразу, коли ми бачимо будь-які виведення на екран відео, це з файлу під назвою /dev/tty і записаного до стандартного виводу на екрані через fd 1.
Запис у stderr => запис у fd 2 : Ми бачимо будь-яку помилку на екрані відео, це також запис із цього файлу в stderr на екрані через fd 2.

Системні виклики введення/виведення

Загалом існує 5 типів системних викликів введення-виведення:

1. Створити

Функція create() використовується для створення нового порожнього файлу в C. Ми можемо вказати дозвіл і назву файлу, який ми хочемо створити, за допомогою функції create(). Визначається всередині файл заголовка та прапори, які передаються як аргументи, визначені всередині файл заголовка.

Синтаксис create() у C

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

Параметр

  • ім'я файлу: ім'я файлу, який ви хочете створити
  • режим: вказує на дозволи для нового файлу.

Повернене значення

  • повертає перший невикористаний дескриптор файлу (зазвичай 3 під час першого створення використання в процесі, оскільки 0, 1, 2 fd зарезервовані)
  • повертає -1 у разі помилки

Як C create() працює в ОС

  • Створіть новий порожній файл на диску.
  • Створити запис таблиці файлів.
  • Встановіть перший невикористаний дескриптор файлу, щоб вказувати на запис таблиці файлів.
  • Використовується дескриптор повернення файлу, -1 у разі помилки.

2. С відкритий

Функція open() у C використовується для відкриття файлу для читання, запису або обох. Він також може створити файл, якщо він не існує. Визначається всередині файл заголовка та прапори, які передаються як аргументи, визначені всередині файл заголовка.

Синтаксис open() у C

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

Параметри

  • Шлях: Шлях до файлу, який ми хочемо відкрити.
    • Використовувати абсолютний шлях починаючи з / коли ви є ні працює в одному каталозі як вихідний файл C.
    • використання відносний шлях це лише ім’я файлу з розширенням, коли ви є працює в одному каталозі як вихідний файл C.
  • прапори: Він використовується для вказівки способу відкриття файлу. Ми можемо використовувати наступні прапори.

Прапори

опис

O_RDONLY Відкриває файл у режимі лише для читання.
О_НЕПРАВИЛЬНО Відкриває файл у режимі лише запису.
O_RDWR Відкриває файл у режимі читання та запису.
O_CREATE Створіть файл, якщо він не існує.
O_EXCL Заборонити створення, якщо воно вже існує.
O_ ДОДАТИ Відкриває файл і встановлює курсор у кінець вмісту.
O_ASYNC Увімкнути керування входом і виходом за сигналом.
O_CLOEXEC Увімкніть режим Close-on-Exec для відкритого файлу.
O_NONBLOCK Вимикає блокування відкритого файлу.
O_TMPFILE Створіть тимчасовий файл без назви за вказаним шляхом.

Як C open() працює в ОС

  • Знайдіть існуючий файл на диску.
  • Створити запис таблиці файлів.
  • Встановіть перший невикористаний дескриптор файлу, щоб вказувати на запис таблиці файлів.
  • Використовується дескриптор повернення файлу, -1 у разі помилки.

Приклад C open()

C


10 у степені 6



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

>

>

Вихід

fd = 3>

3. З закрити

Функція close() у C повідомляє операційній системі, що ви закінчили роботу з файловим дескриптором, і закриває файл, на який вказує файловий дескриптор. Визначається всередині файл заголовка.

Синтаксис close() у C

int close(int fd);>

Параметр

  • fd: F ile дескриптор файлу, який потрібно закрити.

Повернене значення

  • 0 на успіх.
  • -1 на помилку.

Як C close() працює в ОС

  • Знищити запис таблиці файлів, на який посилається елемент fd таблиці дескрипторів файлів
    – Поки жоден інший процес не вказує на це!
  • Встановіть для елемента fd таблиці дескрипторів файлів значення НУЛЬ

Приклад 1: close() у 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. '>);> }>

>

>

Вихід

opened the fd = 3 closed the fd.>

приклад 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);> }>

>

>

Вихід

fd2 = 3>

Тут у цьому коді спочатку повертається open(). 3 оскільки коли створюється головний процес, то fd 0, 1, 2 вже зайняті stdin , stdout, і stderr . Отже, перший невикористаний файловий дескриптор 3 у таблиці дескрипторів файлів. Після цього системний виклик close() звільняється 3 дескриптори файлів, а потім установіть 3 дескриптори файлів як нуль . Отже, коли ми викликали другий open(), перший невикористаний fd також є 3 . Отже, вихід цієї програми такий 3 .

4. С прочитати

З файлу, зазначеного дескриптором файлу fd, функція read() читає вказану кількість байтів cnt введення в область пам’яті, позначену буф . Успішне читання () оновлює час доступу до файлу. Функція read() також визначена всередині файлу заголовка.

Синтаксис read() у C

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

Параметри

  • fd: файловий дескриптор файлу, з якого потрібно зчитувати дані.
  • buf: буфер для читання даних
  • cnt: довжина буфера

Повернене значення

  • return Кількість байтів, прочитаних у разі успіху
  • повертає 0 після досягнення кінця файлу
  • повертає -1 у разі помилки
  • повернення -1 при перериванні сигналу

Важливі моменти

  • буф має вказувати на дійсну область пам’яті довжиною не меншою за вказаний розмір через переповнення.
  • fd має бути дійсним файловим дескриптором, який повертається з open() для виконання операції читання, тому що якщо fd дорівнює NULL, читання має генерувати помилку.
  • cnt це запитана кількість прочитаних байтів, тоді як повернуте значення є фактичною кількістю прочитаних байтів. Крім того, іноді системний виклик read повинен читати менше байтів, ніж cnt.

Приклад read() у C

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

>

>

Вихід

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

Припустимо, що foobar.txt складається з 6 символів ASCII foobar. Тоді що є результатом наступної програми?

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

>

>

Вихід

c = f>

Дескриптори fd1 і fd2 кожен має власний запис таблиці відкритих файлів, тому кожен дескриптор має власну позицію файлу для foobar.txt . Таким чином, читання з fd2 читає перший байт foobar.txt , а вихід є c = f , ні c = o .

5. З писати

Записує cnt байтів із buf у файл або сокет, пов’язаний із fd. cnt не має перевищувати INT_MAX (визначено у файлі заголовка limits.h). Якщо cnt дорівнює нулю, write() просто повертає 0 без будь-яких інших дій.

Write() також визначено всередині файл заголовка.

Синтаксис write() у C

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

Параметри

  • fd: дескриптор файлу
  • buf: буфер для запису даних.
  • cnt: довжина буфера.

Повернене значення

  • повертає кількість байтів, записаних у разі успіху.
  • повертає 0 після досягнення кінця файлу.
  • повертає -1 у разі помилки.
  • повертає -1 при перериванні сигналу.

Напишіть важливі моменти про C

  • Файл потрібно відкрити для операцій запису
  • буф має бути принаймні стільки, скільки вказано cnt, оскільки якщо розмір buf менший за cnt, buf призведе до стану переповнення.
  • cnt це запитана кількість байтів для запису, тоді як повернуте значення є фактичною кількістю записаних байтів. Це відбувається, коли fd має меншу кількість байтів для запису, ніж cnt.
  • Якщо write() переривається сигналом, ефект є одним із наступного:
    • Якщо write() ще не записав жодних даних, він повертає -1 і встановлює для errno значення EINTR.
    • Якщо write() успішно записав деякі дані, він повертає кількість байтів, які він записав до переривання.

Приклад write() у C

C




cpp дорівнює
// 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);> }>

>

>

Вихід

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

Тут, коли ви бачите у файлі foo.txt після виконання коду, ви отримуєте a привіт гіки . Якщо у файлі foo.txt уже є певний вміст, тоді системні виклики write a перезаписують вміст, а весь попередній вміст буде видалено і тільки привіт гіки вміст буде у файлі.

Приклад: надрукувати hello world із програми без використання функції 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;> }>

>

>

Вихід

hello world>

У цьому коді рядок масиву buf1 Привіт Світ спочатку записується в stdin fd[0], потім цей рядок записується в stdin до масиву buf2. Після цього записати в масив buf2 до стандартного виводу та надрукувати вивід Привіт Світ .