Главная · Поиск книг · Поступления книг · Top 40 · Форумы · Ссылки · Читатели

Настройка текста
Перенос строк


    Прохождения игр    
Demon's Souls |#13| Storm King
Demon's Souls |#12| Old Monk & Old Hero
Demon's Souls |#11| Мaneater part 2
Demon's Souls |#10| Мaneater (part 1)

Другие игры...


liveinternet.ru: показано число просмотров за 24 часа, посетителей за 24 часа и за сегодня
Rambler's Top100
Образование - Керниган, Ричи Весь текст 454.51 Kb

Язык Си

Предыдущая страница Следующая страница
1 ... 22 23 24 25 26 27 28  29 30 31 32 33 34 35 ... 39
указателя файла она возвращает дескриптор файла, который яв-
ляется просто целым типа INT.

INT FD;
FD=OPEN(NAME,RWMODE);

Как и в случае FOPEN, аргумент NAME является символьной
строкой, соответствующей внешнему имени файла. Однако аргу-
мент, определяющий режим доступа, отличен: RWMODE равно: 0 -
для чтения, 1 - для записи, 2 - для чтения и записи. Если
происходит какая-то ошибка, функция OPEN возвращает "-1"; в
противном случае она возвращает действительный дескриптор
файла.
    Попытка открыть файл, который не существует, является
ошибкой. Точка входа CREAT предоставляет возможность созда-
ния новых файлов или перезаписи старых. В результате обраще-
ния

FD=CREAT(NAME,PMODE);

возвращает дескриптор файла, если оказалось возможным соз-
дать файл с именем NAME, и "-1" в противном случае. Если
файл с таким именем уже существует, CREAT усечет его до ну-
левой длины; создание файла, который уже существует, не яв-
ляется ошибкой.
    Если файл является совершенно новым, то CREAT создает
его с определенным режимом защиты, специфицируемым аргумен-
том PMODE. В системе файлов на UNIX с файлом связываются де-
вять битов защиты информации, которые управляют разрешением
на чтение, запись и выполнение для владельца файла, для
группы владельцев и для всех остальных пользователей. Таким
образом, трехзначное восьмеричное число наиболее удобно для
спецификации разрешений. Например, число 0755 свидетельству-
ет о разрешении на чтение, запись и выполнение для владельца
и о разрешении на чтение и выполнение для группы и всех ос-
тальных.
    Для иллюстрации ниже приводится программа копирования
одного файла в другой, являющаяся упрощенным вариантом ути-
литы CP системы UNIX. (Основное упрощение заключается в том,
что наш вариант копирует только один файл и что второй аргу-
мент не должен быть справочником).

   #DEFINE NULL 0
   #DEFINE BUFSIZE 512
   #DEFINE PMODE 0644/*RW FOR OWNER,R FOR GROUP,OTHERS*/
   MAIN(ARGC,ARGV) /*CP: COPY F1 TO F2*/
   INT ARGC;
   CHAR *ARGV[];
   \(
  INT F1, F2, N;
  CHAR BUF[BUFSIZE];

  IF (ARGC ! = 3)
  ERROR("USAGE:CP FROM TO", NULL);
  IF ((F1=OPEN(ARGV[1],0))== -1)
  ERROR("CP:CAN'T OPEN %S", ARGV[1]);
  IF ((F2=CREAT(ARGV[2],PMODE))== -1)
  ERROR("CP: CAN'T CREATE %S", ARGV[2]);
  WHILE ((N=READ(F1,BUF,BUFSIZE))>0)
  IF (WRITE(F2,BUF,N) !=N)
       ERROR("CP: WRITE ERROR", NULL);
  EXIT(0);
   \)
   ERROR(S1,S2) /*PRINT ERROR MESSAGE AND DIE*/
   CHAR *S1, S2;
   \(
  PRINTF(S1,S2);
  PRINTF("\N");
  EXIT(1);
   \)

    Существует ограничение (обычно 15 - 25) на количество
файлов, которые программа может иметь открытыми одновремен-
но. В соответствии с этим любая программа, собирающаяся ра-
ботать со многими файлами, должна быть подготовлена к пов-
торному использованию дескрипторов файлов. Процедура CLOSE
прерывает связь между дескриптором файла и открытым файлом и
освобождает дескриптор файла для использования с некоторым
другим файлом. Завершение выполнения программы через EXIT
или в результате возврата из ведущей программы приводит к
закрытию всех открытых файлов.
    Функция расцепления UNLINK (FILENAME) удаляет из системы
файлов файл с именем FILENAME ( из данного справочного фай-
ла. Файл может быть сцеплен с другим справочником, возможно,
под другим именем - примеч.переводчика).

    Упражнение 8-1
    --------------
    Перепишите программу CAT из главы 7, используя функции
READ, WRITE, OPEN и CLOSE вместо их эквивалентов из стандар-
тной библиотеки. Проведите эксперименты для определения от-
носительной скорости работы этих двух вариантов.

     8.4. Произвольный доступ - SEEK и LSEEK

    Нормально при работе с файлами ввод и вывод осуществля-
ется последовательно: при каждом обращении к функциям READ и
WRITE чтение или запись начинаются с позиции, непосредствен-
но следующей за предыдущей обработанной. Но при необходимос-
ти файл может читаться или записываться в любом произвольном
порядке. Обращение к системе с помощью функции LSEEK позво-
ляет передвигаться по файлу, не производя фактического чте-
ния или записи. В результате обращения

 LSEEK(FD,OFFSET,ORIGIN);

текущая позиция в файле с дескриптором FD передвигается на
позицию OFFSET (смещение), которая отсчитывается от места,
указываемого аргументом ORIGIN (начало отсчета). Последующее
чтение или запись будут теперь начинаться с этой позиции.
Аргумент OFFSET имеет тип LONG; FD и ORIGIN имеют тип INT.
Аргумент ORIGIN может принимать значения 0,1 или 2, указывая
на то, что величина OFFSET должна отсчитываться соответст-
венно от начала файла, от текущей позиции или от конца фай-
ла. Например, чтобы дополнить файл, следует перед записью
найти его конец:

 LSEEK(FD,0L,2);

чтобы вернуться к началу ("перемотать обратно"), можно напи-
сать:

 LSEEK(FD,0L,0);

обратите внимание на аргумент 0L; его можно было бы записать
и в виде (LONG) 0.
    Функция LSEEK позволяет обращаться с файлами примерно
так же, как с большими массивами, правда ценой более медлен-
ного доступа. следующая простая функция, например, считывает
любое количество байтов, начиная с произвольного места в
файле.

   GET(FD,POS,BUF,N) /*READ N BYTES FROM POSITION POS*/
   INT FD, N;
   LONG POS;
   CHAR *BUF;
   \(
  LSEEK(FD,POS,0); /*GET TO POS*/
  RETURN(READ(FD,BUF,N));
   \)

    В более ранних редакциях, чем редакция 7 системы UNIX,
основная точка входа в систему ввода-вывода называется SEEK.
Функция SEEK идентична функции LSEEK, за исключением того,
что аргумент OFFSET имеет тип INT, а не LONG. в соответствии
с этим, поскольку на PDP-11 целые имеют только 16 битов, ар-
гумент OFFSET, указываемый функции SEEK, ограничен величиной
65535; по этой причине аргумент ORIGIN может иметь значения
3, 4, 5, которые заставляют функцию SEEK умножить заданное
значение OFFSET на 512 (количество байтов в одном физическом
блоке) и затем интерпретировать ORIGIN, как если это 0, 1
или 2 соответственно. Следовательно, чтобы достичь произ-
вольного места в большом файле, нужно два обращения к SEEK:
сначала одно, которое выделяет нужный блок, а затем второе,
где ORIGIN имеет значение 1 и которое осуществляет передви-
жение на желаемый байт внутри блока.

    Упражнение 8-2
    ---------------
    Очевидно, что SEEK может быть написана в терминалах
LSEEK и наоборот. напишите каждую функцию через другую.

     8.5. Пример - реализация функций FOPEN и GETC

    Давайте теперь на примере реализации функций FOPEN и
GETC из стандартной библиотеки подпрограмм продемонстрируем,
как некоторые из описанных элементов объединяются вместе.
    Напомним, что в стандартной библиотеке файлы описыватся
посредством указателей файлов, а не дескрипторов. Указатель
файла является указателем на структуру, которая содержит
несколько элементов информации о файле: указатель буфера,
чтобы файл мог читаться большими порциями; счетчик числа
символов, оставшихся в буфере; указатель следующей позиции
символа в буфере; некоторые признаки, указывающие режим чте-
ния или записи и т.д.; дескриптор файла.
    Описывающая файл структура данных содержится в файле
STDIO.H, который должен включаться (посредством #INCLUDE) в
любой исходный файл, в котором используются функции из стан-
дартной библиотеки. Он также включается функциями этой биб-
лиотеки. В приводимой ниже выдержке из файла STDIO.H имена,
предназначаемые только для использования функциями библиоте-
ки, начинаются с подчеркивания, с тем чтобы уменьшить веро-
ятность совпадения с именами в программе пользователя.

 DEFINE _BUFSIZE 512
 DEFINE _NFILE   20 /*FILES THAT CAN BE HANDLED*/
  TYPEDEF STRUCT _IOBUF \(
    CHAR *_PTR;   /*NEXT CHARACTER POSITION*/
    INT  _CNT;    /*NUMBER OF CHARACTERS LEFT*/
    CHAR *_BASE;  /*LOCATION OF BUFFER*/
    INT  _FLAG;   /*MODE OF FILE ACCESS*/
    INT  _FD;     /*FILE DESCRIPTOR*/
 ) FILE;
 XTERN FILE _IOB[_NFILE];

 DEFINE   STDIN         (&_IOB[0])
 DEFINE   STDOUT        (&_IOB[1])
 DEFINE   STDERR        (&_IOB[2])

 DEFINE   _READ   01  /* FILE OPEN FOR READING */
 DEFINE   _WRITE  02  /* FILE OPEN FOR WRITING */
 DEFINE   _UNBUF  04  /* FILE IS UNBUFFERED */
 DEFINE   _BIGBUF 010 /* BIG BUFFER ALLOCATED */
 DEFINE   _EOF 020 /* EOF HAS OCCURRED ON THIS FILE */
 DEFINE   _ERR 040 /* ERROR HAS OCCURRED ON THIS FILE */
 DEFINE   NULL 0
 DEFINE   EOF  (-1)

 DEFINE   GETC(P) (--(P)->_CNT >= 0 \
   ? *(P)->_PTR++ & 0377 : _FILEBUF(P))
 DEFINE   GETCHAR() GETC(STDIN)

 DEFINE   PUTC(X,P) (--(P)->_CNT >= 0 \
   ? *(P)->_PTR++ = (X) : _FLUSHBUF((X),P))
 DEFINE   PUTCHAR(X)       PUTC(X,STDOUT)

    В нормальном состоянии макрос GETC просто уменьшает
счетчик, передвигает указатель и возвращает символ. (Если
определение #DEFINE слишком длинное, то оно продолжается с
помощью обратной косой черты). Если однако счетчик становит-
ся отрицательным, то GETC вызывает функцию _FILEBUF, которая
снова заполняет буфер, реинициализирует содержимое структуры
и возвращает символ. Функция может предоставлять переносимый
интерфейс и в то же время содержать непереносимые конструк-
ции: GETC маскирует символ числом 0377, которое подавляет
знаковое расширение, осуществляемое на PDP-11, и тем самым
гарантирует положительность всех символов.
    Хотя мы не собираемся обсуждать какие-либо детали, мы
все же включили сюда определение макроса PUTC, для того что-
бы показать, что она работает в основном точно также, как и
GETC, обращаясь при заполнении буфера к функции _FLUSHBUF.
    Теперь может быть написана функция FOPEN. Большая часть
программы функции FOPEN связана с открыванием файла и распо-
ложением его в нужном месте, а также с установлением битов
признаков таким образом, чтобы они указывали нужное состоя-
ние. Функция FOPEN не выделяет какой-либо буферной памяти;
это делается функцией _FILEBUF при первом чтении из файла.

 #INCLUDE
 #DEFINE  PMODE  0644 /*R/W FOR OWNER;R FOR OTHERS*/
 FILE *FOPEN(NAME,MODE) /*OPEN FILE,RETURN FILE PTR*/
 REGISTER CHAR *NAME, *MODE;
 \(
     REGISTER INT FD;
     REGISTER FILE *FP;
 IF(*MODE !='R'&&*MODE !='W'&&*MODE !='A') \(
     FPRINTF(STDERR,"ILLEGAL MODE %S OPENING %S\N",
    MODE,NAME);
     EXIT(1);
 \)
 FOR (FP=_IOB;FP<_IOB+_NFILE;FP++)
     IF((FP->_FLAG & (_READ \! _WRITE))==0)
    BREAK; /*FOUND FREE SLOT*/
 IF(FP>=_IOB+_NFILE) /*NO FREE SLOTS*/
     RETURN(NULL);
 IF(*MODE=='W') /*ACCESS FILE*/
     FD=CREAT(NAME,PMODE);
 ELSE IF(*MODE=='A') \(
     IF((FD=OPEN(NAME,1))==-1)
    FD=CREAT(NAME,PMODE);
     LSEEK(FD,OL,2);
 \) ELSE
     FD=OPEN(NAME,0);
 IF(FD==-1) /*COULDN'T ACCESS NAME*/
     RETURN(NULL);
 FP->_FD=FD;
 FP->_CNT=0;
 FP->_BASE=NULL;
 FP->_FLAG &=(_READ \! _WRITE);
 FP->_FLAG \!=(*MODE=='R') ? _READ : _WRITE;
 RETURN(FP);
 \)

    Функция _FILEBUF несколько более сложная. Основная труд-
ность заключается в том, что _FILEBUF стремится разрешить
доступ к файлу и в том случае, когда может не оказаться дос-
таточно места в памяти для буферизации ввода или вывода. ес-
ли пространство для нового буфера может быть получено обра-
щением к функции CALLOC, то все отлично; если же нет, то
_FILEBUF осуществляет небуферизованный ввод/ вывод, исполь-
зуя отдельный символ, помещенный в локальном массиве.

  #INCLUDE
  _FILLBUF(FP) /*ALLOCATE AND FILL INPUT BUFFER*/
  REGISTER FILE *FP;
   (
  STATIC CHAR SMALLBUF(NFILE);/*FOR UNBUFFERED 1/0*/
   CHAR *CALLOC();
 IF((FR->_FLAG&_READ)==0\!\!(FP->_FLAG&(EOF\!_ERR))\!=0
    RETURN(EOF);
 WHILE(FP->_BASE==NULL) /*FIND BUFFER SPACE*/
    IF(FP->_FLAG & _UNBUF) /*UNBUFFERED*/
   FP->_BASE=&SMALLBUF[FP->_FD];
    ELSE IF((FP->_BASE=CALLOC(_BUFSIZE,1))==NULL)
    FP->_FLAG \!=_UNBUF; /*CAN'T GET BIG BUF*/
    ELSE
    FP->_FLAG \!=_BIGBUF; /*GOT BIG ONE*/
 FP->_PTR=FP->_BASE;
 FP->_CNT=READ(FP->_FD, FP->_PTR,
    FP->_FLAG & _UNBUF ? 1 : _BUFSIZE);
 FF(--FP->_CNT<0) \(
Предыдущая страница Следующая страница
1 ... 22 23 24 25 26 27 28  29 30 31 32 33 34 35 ... 39
Ваша оценка:
Комментарий:
  Подпись:
(Чтобы комментарии всегда подписывались Вашим именем, можете зарегистрироваться в Клубе читателей)
  Сайт:
 
Комментарии (1)

Реклама