netlib.narod.ru< Назад | Оглавление | Далее >

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, O_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

  void error(char *, ...);

  /* cp: копирование f1 в f2 */
  main(int argc, char *argv[])
  {
      int f1, f2, n;
      char buf[BUFSIZ];

      if (argc != 3)
          error("Вызов: cp источник копия");
      if ((f1 = open(argv[1], O_RDONLY, 0)) == -1)
          error("cp: не могу открыть файл %s", argv[1]);
      if ((f2 = creat(argv[2], PERMS)) == -1)
          error("cp: не могу создать файл %s, режим %03o",
                 argv[2], PERMS);
      while ((n = read(f1, buf, BUFSIZ)) > 0)
          if (write(f2, buf, n) != n)
              error("cp: ошибка при записи в файл %s", argv[2]);
      return 0;
  }

Данная программа создает файл вывода с фиксированными правами доступа, определяемыми кодом 0666. С помощью системного вызова stat, который будет описан в параграфе 8.6, мы можем определить режим использования существующего файла и задать тот же режим для копии.

Заметим, что функция error со списком аргументов переменной длины во многом похожа на printf. Реализация error иллюстрирует, как пользоваться другими программами семейства printf. Библиотечная функция vprintf аналогична printf, с той лишь оговоркой, что переменная часть списка аргументов заменена в ней одним аргументом, который инициализируется макросом va_start. Подобным же образом соотносятся функции vfprintf с fprintf и vsprintf с sprintf.

  #include <stdio.h>
  #include <stdarg.h>

  /* error: печатает сообщение об ошибке и завершает программу */
  void error(char *fmt, ...)
  {
      va_list args;

      va_start(args, fmt);
      fprintf(stderr, "ошибка: ");
      vfprintf(stderr, fmt, args);
      fprintf(stderr, "\n");
      va_end(args);
      exit(1);
  }

На количество одновременно открытых в программе файлов имеется ограничение (обычно их число колеблется около 20). Поэтому любая программа, которая намеревается работать с большим количеством файлов, должна быть готова повторно использовать их дескрипторы. Функция close (int fd) разрывает связь между файловым дескриптором и открытым файлом и освобождает дескриптор для его применения с другим файлом. Она аналогична библиотечной функции fclose с тем лишь различием, что никакой очистки буфера не делает. Завершение программы с помощью exit или return в главной функции закрывает все открытые файлы.

Функция unlink(char *name) удаляет имя файла из файловой системы. Она соответствует функции remove стандартной библиотеки.


Упражнение 8-1


Перепишите программу cat из главы 7, используя функции read, write, open и close. Замените ими соответствующие функции стандартной библиотеки. Поэкспериментируйте, чтобы сравнить быстродействие двух версий.



netlib.narod.ru< Назад | Оглавление | Далее >

Сайт управляется системой uCoz