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

Язык С
Строк программы, исключая математическое обеспечение Является учебным введением в центральную часть языка “C” Hачинаем. Единственный способ освоить новый язык Оператор FOR Набор полезных программ Подсчет символов Подсчет слов Функции Аргументы - вызов по значению Область действия: внешние переменные Резюме Константы Описания Преобразование типов До 9 и буквы от а до F Операции и выражения присваивания Старшинство и порядок вычисления Операторы и блоки Переключатель Цикл DO - WHILE Оператор CONTINUE Основные сведения Функции, возвращающие нецелые значения Еще об аргументах функций Правила, определяющие область действия Статические переменные Блочная структура Рекурсия Указатели и адреса Указатели и массивы Адресная арифметика Указатели символов и функции Указатели - не целые До 12, а не от 0 до 11. Так как за экономию памяти у нас пока не награждают, такой способ проще, чем подгонка индек-сов Инициализация массивов указателей Указатели на функции Структуры Структуры и функции Указатели на структуры Мы продемонстрируем, как правильно выполнить эту задачу Поля Определение типа Обращение к стандартной библиотеке Форматный вывод - функция PRINTF Форматный ввод - функция SCANF Форматное преобразование в памяти Обработка ошибок - STDERR и EXIT Обращение к системе Низкоуровневый ввод/вывод - операторы READ и WRITE Произвольный доступ - SEEK и LSEEK Пример - распечатка справочников Пример - распределитель памяти Константы Синтаксическая нотация Преобразования Первичные выражения Унарные операции Аддитивные операции Операция присваивания Спецификаторы типа Описание структур и объединений Инициализация TYPEDEF Оператор SWITCH Внешнее определение функции Область действия внешних идентификаторов Неявные описания Явные преобразования указателей Анахронизмы Операторы
439386
знаков
0
таблиц
0
изображений

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

Нормально при работе с файлами ввод и вывод осуществля-

ется последовательно: при каждом обращении к функциям READ и

WRITE чтение или запись начинаются с позиции, непосредствен-

но следующей за предыдущей обработанной. Но при необходимос-

ти файл может читаться или записываться в любом произвольном

порядке. Обращение к системе с помощью функции LSEEK позво-

ляет передвигаться по файлу, не производя фактического чте-

ния или записи. В результате обращения

 

LSEEK(FD,OFFSET,ORIGIN);

·    
172 -

текущая позиция в файле с дескриптором 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 и наоборот. напишите каждую функцию через другую.

·    
173 -

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)

·      
174 -

В нормальном состоянии макрос GETC просто уменьшает

счетчик, передвигает указатель и возвращает символ. (Если

определение #DEFINE слишком длинное, то оно продолжается с

помощью обратной косой черты). Если однако счетчик становит-

ся отрицательным, то GETC вызывает функцию _FILEBUF, которая

снова заполняет буфер, реинициализирует содержимое структуры

и возвращает символ. Функция может предоставлять переносимый

интерфейс и в то же время содержать непереносимые конструк-

ции: GETC маскирует символ числом 0377, которое подавляет

знаковое расширение, осуществляемое на PDP-11, и тем самым

гарантирует положительность всех символов.

Хотя мы не собираемся обсуждать какие-либо детали, мы

все же включили сюда определение макроса PUTC, для того что-

бы показать, что она работает в основном точно также, как и

GETC, обращаясь при заполнении буфера к функции _FLUSHBUF.

Теперь может быть написана функция FOPEN. Большая часть

программы функции FOPEN связана с открыванием файла и распо-

ложением его в нужном месте, а также с установлением битов

признаков таким образом, чтобы они указывали нужное состоя-

ние. Функция FOPEN не выделяет какой-либо буферной памяти;

это делается функцией _FILEBUF при первом чтении из файла.

 

#INCLUDE <STDIO.H>

#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);

\)

·     175 -

 

Функция _FILEBUF несколько более сложная. Основная труд-

ность заключается в том, что _FILEBUF стремится разрешить

доступ к файлу и в том случае, когда может не оказаться дос-

таточно места в памяти для буферизации ввода или вывода. ес-

ли пространство для нового буфера может быть получено обра-

щением к функции CALLOC, то все отлично; если же нет, то

_FILEBUF осуществляет небуферизованный ввод/ вывод, исполь-

зуя отдельный символ, помещенный в локальном массиве.

 

#INCLUDE <STDIO.H>

_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) \(

IF(FP->_CNT== -1)

FP->_FLAG \! = _EOF;

ELSE

FP->_FLAG \! = _ ERR;

FP->_CNT = 0;

RETURN(EOF);

\)

RETURN(*FP->_PTR++ & 0377); /*MAKE CHAR POSITIVE*/

)

 

При первом обращении к GETC для конкретного файла счетчик

оказывается равным нулю, что приводит к обращению к

_FILEBUF. Если функция _FILEBUF найдет, что этот файл не от-

крыт для чтения, она немедленно возвращает EOF. В противном

случае она пытается выделить большой буфер, а если ей это не

удается, то буфер из одного символа. При этом она заносит в

_FLAG соответствующую информацию о буферизации.

Раз буфер уже создан, функция _FILEBUF просто вызывает

функцию READ для его заполнения, устанавливает счетчик и

указатели и возвращает символ из начала буфера.

Единственный оставшийся невыясненным вопрос состоит в

том, как все начинается. Массив _IOB должен быть определен и

инициализирован для STDIN, STDOUT и STDERR:

·    
176 -

FILE _IOB[NFILE] = \(

(NULL,0,_READ,0), /*STDIN*/

(NULL,0,NULL,1), /*STDOUT*/

(NULL,0,NULL,_WRITE \! _UNBUF,2) /*STDERR*/

);

 

Из инициализации части _FLAG этого массива структур видно,

что файл STDIN предназначен для чтения, файл STDOUT - для

записи и файл STDERR - для записи без использования буфера.

Упражнение 8-3.

Перепишите функции FOPEN и _FILEBUF, используя поля

вместо явных побитовых операций.

Упражнение 8-4.

Разработайте и напишите функции _FLUSHBUF и FCLOSE.

Упражнение 8-5.

Стандартная библиотека содержит функцию

FSEEK(FP, OFFSET, ORIGIN)

которая идентична функции LSEEK, исключая то, что FP являет-

ся указателем файла, а не дескриптором файла. Напишите

FSEEK. Убедитесь, что ваша FSEEK правильно согласуется с бу-

феризацией, сделанной для других функций библиотеки.

 


Информация о работе «Язык С»
Раздел: Информатика, программирование
Количество знаков с пробелами: 439386
Количество таблиц: 0
Количество изображений: 0

Похожие работы

Скачать
48443
0
0

... основаниям. При этом философская абстракция языка оказывается неразрывно связана с основными темами и движениями философии в целом. Более конкретно, на ранние стадии традиционно рассматриваемого в рамках АФ анализа обыденного языка глубокое влияние оказала философия Дж. Э. Мура, особенно его учение о здравом смысле, согласно которому такие понятия, как «человек», «мир», «я», «внешний мир», « ...

Скачать
43709
0
0

... и других странах СНГ, а также облегчение доступа к русской и мировой культуре и науке. Таким образом, судя по данным наших исследований, востребованность русского языка осталась в республике достаточно высокой. Многие представители современной молдавской молодежи продолжают, как их отцы и деды, тянуться к русской культуре, научным и техническим достижениям России. Русский язык остается языком ...

Скачать
39778
0
1

... рисуночное словесно-слоговое письмо). Памятники среднеэламского периода (14—12 вв. до н.э.) выполнены аккадской клинописью. Памятники новоэламского периода относятся к 8—6 вв. до н.э. Был официальным языком в персидском государстве Ахеменидов в 6—4 вв. предполагается, что он, подвергшись влиянию древнеперсидского, сохранился до раннего средневековья. 7. Бурушаски язык Язык бурушаски ( ...

Скачать
64931
0
0

... /диалект), скифский, согдийский, среднеперсидский, таджикский, таджриши (язык/диалект), талышский, татский, хорезмийский, хотаносакский, шугнано-рушанская группа языков, ягнобский, язгулямский и др. Они относятся к индоиранской ветви индоевропейских языков. Области распространения: Иран, Афганистан, Таджикистан, некоторые районы Ирака, Турции, Пакистана, Индии, Грузии, Российской Федерации. Общее ...

0 комментариев


Наверх