Язык программирования C



         

Низкоуровневый ввод/вывод - операторы READ и WRITE


Самый низкий уровень ввода/вывода в системе UNIX не предусматривает ни какой-либо буферизации, ни какого-либо другого сервиса; он по существу является непосредственным входом в операционную систему. Весь ввод и вывод осуществляется двумя функциями: read и write. Первым аргументом обеих функций является дескриптор файла. Вторым аргументом является буфер в вашей программе, откуда или куда должны поступать данные. Третий аргумент - это число подлежащих пересылке байтов. Обращения к этим функциям имеют вид:

n_read=read(fd,buf,n); n_written=write(fd,buf,n);

При каждом обращении возвращается счетчик байтов, указывающий фактическое число переданных байтов. При чтении возвращенное число байтов может оказаться меньше, чем запрошенное число. Возвращенное нулевое число байтов означает конец файла, а "-1" указывает на наличие какой-либо ошибки. При записи возвращенное значение равно числу фактически записанных байтов; несовпадение этого числа с числом байтов, которое предполагалось записать, обычно свидетельствует об ошибке.

Количество байтов, подлежащих чтению или записи, может быть совершенно произвольным. Двумя самыми распространенными величинами являются "1", которая означает передачу одного символа за обращение (т.е. без использования буфера), и "512", которая соответствует физическому размеру блока на многих периферийных устройствах. Этот последний размер будет наиболее эффективным, но даже ввод или вывод по одному символу за обращение не будет необыкновенно дорогим.

Объединив все эти факты, мы написали простую программу для копирования ввода на вывод, эквивалентную программе копировки файлов, написанной в лекции №1. На системе UNIX эта программа будет копировать что угодно куда угодно, потому что ввод и вывод могут быть перенаправлены на любой файл или устройство.

#define bufsize 512 /*best size for pdp-11 unix*/ main() /*copy input to output*/ { char buf[bufsize]; int n; while((n=read(0,buf,bufsize))>0) write(1,buf,n); }

Если размер файла не будет кратен bufsize, то при некотором обращении к read будет возвращено меньшее число байтов, которые затем записываются с помощью write; при следующем после этого обращении к read будет возвращен нуль.

Поучительно разобраться, как можно использовать функции read и write для построения процедур более высокого уровня, таких как getchar, putchar и т.д. Вот, например, вариант функции getchar, осуществляющий ввод без использования буфера.

#define cmask 0377 /*for making char's > 0*/ getchar() /*unbuffered single character input*/ { char c; return((read(0,&c,1)>0 ? c & cmask : EOF); }

Переменная "C" должна быть описана как char, потому что функция read принимает указатель на символы. Возвращаемый символ должен быть маскирован числом 0377 для гарантии его положительности; в противном случае знаковый разряд может сделать его значение отрицательным. (константа 0377 подходит для эвм PDP-11, но не обязательно для других машин).

Второй вариант функции getchar осуществляет ввод большими порциями, а выдает символы по одному за обращение.

#define cmask 0377 /*for making char's>0*/ #define bufsize 512 getchar() /*buffered version*/ { static char buf[bufsize]; static char *bufp = buf; static int n = 0; if (n==0) { /*buffer is empty*/ n=read(0,buf,bufsize); bufp = buf; } return((--n>=0) ? *bufp++ & cmask : EOF); }




Содержание  Назад  Вперед