Полезно рассмотреть, как используются read
и write при написании программ более высокого уровня - таких как getchar, putchar и т. д. Вот, к примеру, версия программы getchar, которая осуществляет небуферизованный ввод, читая по одному символу из стандартного входного потока.#include "syscalls.h"
/* getchar: небуферизованный ввод одного символа */
int getchar(void) {
char с;
return (read(0, &c, 1) == 1) ? (unsigned char) с: EOF;
}
Переменная c
должна быть типа char, поскольку read требует указателя на char. Приведение c к unsigned char перед тем, как вернуть ее в качестве результата, исключает какие-либо проблемы, связанные с распространением знака.Вторая версия getchar
осуществляет ввод большими кусками, но при каждом обращении выдает только один символ.#include "syscalls.h"
/* getchar: простая версия с буферизацией */
int getchar(void)
{
static char buf[BUFSIZ];
static char *bufp = buf;
static int n = 0;
if (n == 0) { /* буфер пуст */
n = read(0, buf, sizeof buf);
bufp = buf;
}
return (--n ›= 0) ? (unsigned char) *bufp++ : EOF;
}
Если приведенные здесь версии функции getchar компилируются с включением заголовочного файла ‹stdio.h› и в этом заголовочном файле getchar
определена как макрос, то нужно задать строку #undef с именем getchar.8.3 Системные вызовы open, creat, close, unlink
В отличие от стандартных файлов ввода, вывода и ошибок, которые открыты по умолчанию, остальные файлы нужно открывать явно. Для этого есть два системных вызова: open
и creat.Функция open
почти совпадает с fopen, рассмотренной в главе 7. Разница между ними в том, что первая возвращает не файловый указатель, а дескриптор файла типа int. При любой ошибке open возвращает -1.include ‹fcntl.h›
int fd;
int open(char *name, int flags, int perms);
fd = open(name, flags, perms);
Как и в fopen
, аргумент name - это строка, содержащая имя файла. Второй аргумент, flags, имеет тип int и специфицирует, каким образом должен быть открыт файл. Его основными значениями являются:O_RDONLY - открыть только на чтение;
O_WRONLY - открыть только на запись;
O_RDWR - открыть и на чтение, и на запись.
В System V UNIX эти константы определены в ‹fcntl.h›, а в версиях Berkley (BSD) - в ‹sys/file.h›.
Чтобы открыть существующий файл на чтение, можно написать
fd = open(name, 0_RDONLY, 0);
Далее везде, где мы пользуемся функцией open
, ее аргумент perms равен нулю.Попытка открыть несуществующий файл является ошибкой. Создание нового файла или перезапись старого обеспечивается системным вызовом creat
. Напримерint creat(char *name, int perms);
fd = creat(name, perms);
Функция creat
возвращает дескриптор файла, если файл создан, и -1, если по каким-либо причинам файл создать не удалось. Если файл уже существует, creat "обрежет" его до нулевой длины, что равносильно выбрасыванию предыдущего содержимого данного файла; создание уже существующего файла не является ошибкой.Если строится действительно новый файл, то creat
его создаст с правами доступа, специфицированными в аргументе perms. В системе UNIX с каждым файлом ассоциированы девять битов, содержащие информацию о правах пользоваться этим файлом для чтения, записи и исполнения лицам трех категорий: собственнику файла, определенной им группе лиц и всем остальным. Таким образом, права доступа удобно специфицировать с помощью трех восьмеричных цифр. Например, 0755 специфицирует чтение, запись и право исполнения собственнику файла, а также чтение и право исполнения группе и всем остальным.Для иллюстрации приведем упрощенную версию программы cp
системы UNIX, которая копирует один файл в другой. В нашей версии копируется только один файл, не позволяется во втором аргументе указывать директорий (каталог), и права доступа не копируются, а задаются константой.#include ‹stdio.h›
#include ‹fcntl.h›
#include "syscalls.h"
#define PERMS 0666 /* RW для собственника, группы и остальных */
void error(char *,…);
/* cp: копирование f1 в f2 */
main(int argc, char *argv[])
{
int f1, f2, n;