Лекция 6: Организация ввода-вывода в Си
"Кто рано встает — тому весь день спать хочется."
— Джейсон Стейтем
Введение в ввод-вывод (ВВ) в C
Ввод-вывод (input-output, IO/ВВ) — это взаимодействие между обработчиком информации (например, компьютером) и внешним миром (человеком или другой системой обработки информации). ВВ включает получение данных системой (ввод) и отправку данных из системы (вывод).
Подсистема ввода-вывода играет ключевую роль в производительности вычислительных систем, так как определяет время отклика и общее быстродействие. Все операции ввода-вывода в Си организованы через потоки — последовательности байтов, которые связываются с устройствами ввода-вывода или файлами. Буферизация потоков позволяет ускорить работу, минимизируя обращения к внешним устройствам.
Типы систем ввода-вывода
Основные подходы:
- Обработка ВВ центральным процессором (CPU)
- Обработка ВВ специальными процессорами ВВ (IOP), как в AS/400 или S/390.
- Параллельная обработка ВВ, что позволяет увеличивать производительность.
Основные функции подсистемы ВВ
- Организация параллельной работы устройств ВВ и процессора.
- Согласование скоростей обмена и кэширование данных.
- Разделение устройств и данных между процессами.
- Обеспечение логического интерфейса для взаимодействия.
- Поддержка драйверов и различных файловых систем.
- Поддержка синхронных и асинхронных операций ВВ.
Средства ввода-вывода в языке C
Стандартные потоки
При запуске программы в Си создаются три стандартных потока:
stdin
— стандартный поток ввода (клавиатура).stdout
— стандартный поток вывода (экран).stderr
— поток вывода сообщений об ошибках.
#include <stdio.h>
int main() {
printf("Введите символ: ");
int c = getchar();
printf("Вы ввели: ");
putchar(c);
return 0;
}
Форматированный ввод и вывод
Функции форматированного ввода и вывода:
scanf
— ввод данных с форматированием.printf
— вывод данных с форматированием.
Пример:
#include <stdio.h>
int main() {
int a;
float b;
printf("Введите целое число и число с плавающей точкой: ");
scanf("%d %f", &a, &b);
printf("Целое число: %d, число с плавающей точкой: %.2f\n", a, b);
return 0;
}
Работа с файлами
Файлы обрабатываются через указатели типа FILE*
. Основные операции:
Открытие и закрытие файлов
FILE *fp;
fp = fopen("example.txt", "w");
if (fp == NULL) {
perror("Ошибка открытия файла");
return -1;
}
fclose(fp);
Чтение и запись данных
Чтение из файла:
char buffer[100];
fp = fopen("example.txt", "r");
if (fp == NULL) {
perror("Ошибка открытия файла");
return -1;
}
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
printf("%s", buffer);
}
fclose(fp);
Запись в файл:
fp = fopen("example.txt", "w");
if (fp == NULL) {
perror("Ошибка открытия файла");
return -1;
}
fprintf(fp, "Запись в файл\n");
fclose(fp);
Низкоуровневый ввод-вывод
Функции низкоуровневого ввода-вывода (open
, read
, write
, close
) напрямую взаимодействуют с ОС.
Пример:
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
int main() {
int fd = open("example.txt", O_RDONLY);
if (fd == -1) {
perror("Ошибка открытия файла");
return -1;
}
char buffer[100];
int bytesRead = read(fd, buffer, sizeof(buffer) - 1);
if (bytesRead > 0) {
buffer[bytesRead] = '\0';
printf("Содержимое файла: %s\n", buffer);
}
close(fd);
return 0;
}
Буферизация и обработка ошибок
Буферизация потоков позволяет ускорить операции ВВ. Ошибки проверяются с помощью функций ferror
и clearerr
:
FILE *fp = fopen("example.txt", "r");
if (fp == NULL) {
perror("Ошибка открытия файла");
return -1;
}
int ch = fgetc(fp);
if (ch == EOF) {
if (ferror(fp)) {
perror("Ошибка чтения файла");
clearerr(fp);
} else {
printf("Достигнут конец файла.\n");
}
}
fclose(fp);
Различия текстовых и бинарных потоков
- Текстовый поток преобразует данные (например,
\n
-> CR+LF). - Бинарный поток сохраняет данные без преобразования.
Пример открытия в текстовом и бинарном режимах:
FILE *textFile = fopen("text.txt", "w");
FILE *binaryFile = fopen("binary.bin", "wb");
Заключение
Подсистема ввода-вывода в языке C включает как высокоуровневые функции стандартной библиотеки (stdio.h
), так и низкоуровневые системные вызовы. Эти механизмы обеспечивают гибкость и производительность при работе с файлами и устройствами.