Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Информатика_ч2-записи

.pdf
Скачиваний:
4
Добавлен:
15.04.2015
Размер:
417.35 Кб
Скачать

11

текущего компонента в переменную Z, указатель файла устанавливается на следующий компонент (запись).

Write (F, Z) - записать новый компонент в файл. Переменные Zl, Z2, ... , ZN записываются в дисковый файл, определенный переменной F. После выполнения процедуры указатель перемещается к следующему компоненту.

Seek (F, k) - установить указатель на компонент Zk с порядковым номером k в файле. Указатель перемещается к компоненту с номером k, начиная счет с нуля, т. е. первый компонент имеет номер 0, второй - 1, третий - 2 и т. д.

Close(F) - закрыть файл. Выполнение процедуры обеспечивает закрытие файла, назначенного переменной F. Если файл был открыт, никогда не следует выходить из программы, предварительно не закрыв его.

Erase(F) - уничтожить файл. Выполнение процедуры вызывает уничтожение файла, назначенного переменной F. Если производится уничтожение открытого файла, его необходимо предварительно закрыть с помощью процедуры Close.

Rename(F, ST) - переименовать файл. Выполнение процедуры вызывает занесение в каталог диска (директорий) нового имени файла, определенного переменной F. Новое имя определяется значением текста в строке ST.

Truncate (F) - уничтожить все компоненты файла, начиная с места текущего положения указателя, и подготовить файл для записи.

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

Eof (F) - проверить маркер "конец файла". Значение функции равно True, если указатель файла находится сразу за последним компонентом файла, и False в любом другом случае.

FilePos (F) - определить текущий номер компонента. Функция возвращает целочисленное значение, равное номеру компонента, на котором установлен в данный момент указатель файла, соответствующего переменной F. Отсчет номера компонента начинается с нуля.

FileSize (F) - определить размер файла. Функция возвращает целочисленное значение, равное количеству компонентов файла, соответствующего переменной F. Эта функция обычно используется для проверки, содержит файл какую-либо информацию или является пустым. Если FileSize (F) = 0, то файл пуст, в другом случае файл содержит данные.

lOResult (F) - проверить результат выполнения последней операции ввода-вывода на наличие ошибок. Если ошибка обнаружена, функция возвращает номер ошибки, если ошибок нет, возвращает значение 0. Эта функция используется при пассивном состоянии директивы {$I-} для организации обработки ошибок ввода-вывода самим пользователем. Если программа для обработки ошибок отсутствует, наличие ошибки ввода-вывода не вызывает прерывания программы и выполняется следующий оператор.

11.3. Организация последовательного доступа к компонентам файла

Режим последовательного доступа используются для решения задач, требующих поочередной обработки компонентов файла при отсутствии жестких ограничений на

12

время решения. Работа с последовательными файлами предполагает создание файла, обработку и возможно корректировку всех его компонентов.

Для создания последовательного файла необходимо выполнить следующие шаги: присвоить файлу имя (процедура Assign); открыть новый файл (процедура

Rewrite); подготовить информацию для ввода; записать в файл компоненты (оператор write); закрыть созданный файл (процедура Close).

Пример 119. Ввести с клавиатуры в соответствии с табл. 48 сведения о 20 студентах и сохранить эту информацию в файле STUDENTS.DAT в корневом каталоге диска A.

Таблица 48.

Номер

Фамилия студента

Дата

Номер

Размер

зачетной

 

рождения

группы

стипендии,

книжки

 

 

 

руб.

TAB

FIO

DATA

GRUP

STEPA

100000

АФАНАСЬЕВ

01.02.83

ПИ-11

500.00

100001

СЫЧЕВ

13.03.84

ПИ-11

500.00

100002

ВАСИЛЬЕВ

15.01.84

ПИ-11

350.00

100003

УШАКОВ

12.12.83

ПИ-11

0.00

100004

СИДОРОВ

01.11.83

ПИ-11

500.00

100005

ГАВРИЛОВ

10.12.83

ПИ-11

850.00

100006

ИВАНОВА

15.05.84

ПИ-11

500.00

100007

ВЕЙНЕРМАН

09.06.83

ПИ-11

500.00

100008

ЯКУШЕВ

24.10.83

ПИ-11

0.00

100009

ЗИБЕРМАН

13.09.84

ИС-11

0.00

100010

АНИСИМОВ

11.04.84

ИС-11

500.00

100011

ПЕТРОВ

03.05.84

ИС-11

350.00

100012

БУНАКОВ

21.06.83

ИС-11

850.00

100013

ФАДЕЕВ

04.10.83

ИС-11

350.00

100014

СЕМЕНОВ

30.01.84

ИС-11

500.00

100015

ЩУКИНА

15.03.84

ИС-11

0.00

100016

ВАХРУШЕВА

13.02.84

ИС-11

350.00

100017

ВЫСОЦКИЙ

06.08.83

ИС-11

850.00

100018

СЕРЕГИНА

05.04.84

ИС-11

500.00

100019

ГОРОХОВ

15.09.83

ИС-11

500.00

Ниже приведен код программы, выполняющий эту задачу. В качестве рабочей таблицы для промежуточного хранения информации о студентах используется массив записей MSTD. Программа работает в два в два этапа. Первый этап состоит в вводе информации о всех 20 студентах (цикл FOR). На втором этапе создается новый файл A:\STUDENTS.DAT и содержимое таблицы MSTD строка за строкой переносится в этот файл.

PROGRAM PR119;

TYPE STUDENT = RECORD

TAB:

LONGINT;

{НОМЕР ЗАЧЕТНОЙ КНИЖКИ}

FIO:

STRING[20];

{ФАМИЛИЯ И.О.}

DATA: STRING[8];

{ДАТА РОЖДЕНИЯ}

GRUP: STRING[7];

{НОМЕР ГРУППЫ}

STEPA: REAL

{РАЗМЕР СТИПЕНДИИ, РУБ.}

END;

 

 

13

VAR MSTD: ARRAY[0..19] OF STUDENT; I: INTEGER; FSTD: FILE OF STUDENT;

BEGIN {ИНИЦИАЛИЗАЦИЯ ТАБЛИЦЫ} WRITELN('ВВЕДИТЕ ДАННЫЕ О 20 СТУДЕНТАХ'); FOR I := 0 TO 19

DO WITH MSTD[I] {ВВОД ДАННЫХ В I-ю СТРОКУ ТАБЛИЦЫ} DO BEGIN

WRITE(I+1: 2,'. НОМЕР ЗАЧЕТНОЙ КНИЖКИ: '); READLN(TAB);

WRITE ('

ФАМИЛИЯ И.О.

: ');

READLN(FIO);

WRITE ('

ДАТА РОЖДЕНИЯ

: ');

READLN(DATA);

WRITE ('

НОМЕР ГРУППЫ

: ');

READLN(GRUP);

WRITE ('

РАЗМЕР СТИПЕНДИИ,РУБ.: '); READLN(STEPA)

END;

 

 

 

{ЗАПИСЬ ТАБЛИЦЫ MSTD В ФАЙЛ} ASSIGN(FSTD, 'A:\STUDENTS.DAT'); REWRITE(FSTD);

FOR I := 0 TO 19

DO IF LENGTH(MSTD[I].FIO) > 0 THEN WRITE(FSTD, MSTD[I]);

CLOSE(FSTD)

END.

В результате выполнения программы в файл STUDENTS.DAT будет занесена информация из табл. 1.

Пример 120. В файле STUDENTS.DAT, расположенном в корневом каталоге диска A хранятся сведения о 20 студентах (см. табл. 1). Требуется вывести на экран монитора в алфавитном порядке фамилии студентов группы ИС-11 и номера их зачетных книжек, которые получают стипендии указанного размера.

Решение этой задачи осуществляется в три этапа. На первом этапе следует прочитать по порядку все записи из файла режиме последовательного доступа. Каждую запись проанализировать на условия отбора (то есть, отфильтровать). При выполнении условий GRUP = 'ИС-11' и STEPA = 1000 запись о студенте следует поместить в промежуточный массив записей MSTD. Подсчитать K - число записей в массиве.

На втором этапе, если K > 1, следует отсортировать записи в массиве MSTD в порядке возрастания значений поля FIO.

На последнем этапе в зависимости от значения K следует на экран монитора вывести сообщения:

при K = 0 - 'В группе ИС-11 нет студентов не получающих стипендию 1000руб.'; при K > 0 - список студентов, содержащий поля FIO (Фамилия) и TAB (Номер

зачетной книжки). PROGRAM PR120;

TYPE STUDENT = RECORD

TAB:

LONGINT;

{НОМЕР ЗАЧЕТНОЙ КНИЖКИ}

FIO:

STRING[20];

{ФАМИЛИЯ И.О.}

DATA: STRING[8];

{ДАТА РОЖДЕНИЯ}

GRUP: STRING[7];

{НОМЕР ГРУППЫ}

 

14

STEPA: REAL

{РАЗМЕР СТИПЕНДИИ, РУБ.}

END;

 

VAR STD, RAB: STUDENT; MSTD: ARRAY[0..19] OF STUDENT; FSTD: FILE OF STUDENT; SFILE, SGR: STRING;

I, J, K: LONGINT; STP: REAL; BEGIN

WRITELN('ВВЕДИТЕ ДИСК, ПУТЬ И ИМЯ ФАЙЛА'); READLN(SFILE); WRITELN('УКАЖИТЕ НОМЕР ГРУППЫ'); READLN(SGR); WRITELN('УКАЖИТЕ РАЗМЕР СТИПЕНДИИ'); READLN(STP);

{ЧТЕНИЕ ДАННЫХ ИЗ ФАЙЛА} ASSIGN(FSTD, SFILE);

RESET(FSTD); K:=0; {Число записей удовлетворяющих условиям поиска} WHILE NOT EOF(FSTD)

DO BEGIN READ(FSTD, STD);

IF (STD.GRUP = SGR) AND (STD.STEPA = STP) THEN BEGIN

MSTD[K]:=STD; {Копирование записи STD в массив MSTD} K := K + 1

END END; CLOSE(FSTD); IF K > 0 THEN BEGIN

FOR I := 1 TO K-1

DO FOR J := K-1 DOWNTO I

DO IF MSTD[J-1].FIO > MSTD[J].FIO

THEN BEGIN {Перестановка записей местами}

RAB := MSTD[J-1]; MSTD[J-1] := MSTD[J]; MSTD[J] := RAB END

END; IF K>0

THEN FOR I:= 0 TO K-1

DO WRITELN(MSTD[I].FIO: 22, MSTD[I].TAB:9, MSTD[I].STEPA: 9: 2)

ELSE WRITELN('В группе ', SGR,' нет студентов имеющих стипендию ', STP: 2: 2,

'руб.')

END.

Если задать значения SGR = 'ИС-11' и STP = 500, то результатом работы программы будет таблица представленная на рис. 35.

15

Рис. 35. Результат работы программы

11.4. Организация прямого доступа к компонентам файла

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

Работа с файлом произвольного доступа предполагает его создание, просмотр и корректировку. Организовать файл произвольного доступа можно двумя способами:

Создать последовательный файл и обращаться к компонентам по их порядковому номеру, трактуя последовательный файл как произвольный;

Создать дополнительный, так называемый индексный файл, содержащий записи с двумя полями. Первое поле индексного файла - ключевое, второе поле номер записи в основном информационном файле.

Ключевое поле содержит упорядоченные значения реквизитов представляющих собой значения одного из полей записей основного файла. Эти значения могут быть уникальными - в этом случае говорят, что это первичный ключ и его можно использовать для идентификации объекта. В некоторых задачах значения в ключевом поле могут повторяться, в этом случае ключ не является уникальным, но помогает быстро найти все записи основного файла, имеющие указанное значение. Таким образом, поиск интересующих нас объектов начинается по значению ключа в индексном файле. Когда запись в индексном файле найдена, то во втором поле находится номер записи в основном файле. Это значение используется процедурой Seek - установка указателя файла на компонент по его номеру.

Индексные файлы нужны для ускорения процедуры поиска требуемых записей в основном файле. Записи основного файла содержат много информационных полей и считываются с диска в буфер оперативной памяти в небольшом количестве. Поэтому просмотр таких записей и поиск по значению поля занимает большое время. Индексные файлы по размеру на один или два порядка меньше, поэтому анализ и поиск номеров записей в них гораздо быстрее (в тысячи раз).

Ключевые поля индексного файла бывают простые и составные. Простой ключ представляет собой значение только одного поля основного набора, или части этого поля. Составной ключ - это комбинация двух и более полей, или их частей. Составной ключ формируется с двумя целями. Во-первых придать записи уникальный префикс, играющий роль идентификатора. Например, фамилия + имя + отчество - позволяют в достаточно

16

большом коллективе около 4000 человек, где десять Ивановых, восемь Петровых и два Гаскарова, выбрать одного единственного сотрудника. Во-вторых упорядочить все записи файла в соответствии с требованиями. Например, требуется, упорядочить всех сотрудников по фамилии, для совпадающих фамилий по инициалам.

Имя индексного файла обычно формируется следующим образом. Собственное имя, до восьми литер, часто повторяет имя основного базового файла. Напомним, что в нашем примере базовый файл имеет имя STUDENTS.DAT. Последние три символа определяют тип файла. Для индексных файлов тоже существуют свои расширения, принятые в соответствующих системах программирования баз данных. Мы будем использовать расширение .NTX, позаимствовав его у индексных файлов CLIPPER. Таким образом, полное имя нашего индексного файла будет STUDENTS.NTX.

Приведем структуру индексного файла STUDENTS.NTX и его данные, построенного для табл. 48, соответствующей файлу STUDENTS.DAT (см. табл. 49).

Таблица 49.

Фамилия студента

Номер записи

FIO

NAMBER

АНИСИМОВ

10

АФАНАСЬЕВ

0

БУНАКОВ

12

ВАСИЛЬЕВ

2

ВАХРУШЕВА

16

ВЕЙНЕРМАН

7

ВЫСОЦКИЙ

17

ГАВРИЛОВ

5

ГОРОХОВ

19

ИВАНОВА

6

ЗИБЕРМАН

9

ПЕТРОВ

11

СЕМЕНОВ

14

СЕРЕГИНА

18

СИДОРОВ

4

СЫЧЕВ

1

УШАКОВ

3

ФАДЕЕВ

13

ЩУКИНА

15

ЯКУШЕВ

8

В дополнение к вышесказанному следует отметить, что индексных файлов может быть несколько. Столько сколько нужно для решения ваших задач. А вот основной файл всегда один. Этим избегается дублирование информации об объекте и облегчается ее корректировка. Но это же накладывает особые требования к системе программ обслуживающих основные и индексные файлы.

11.5. Создание индексного файла

Процесс первоначального создания индексного файла называется индексацией. При работе с базой данных существует невидимая информационная (реляционная) связь между двумя таблицами (файлами STUDENTS.DAT и STUDENTS.NTX), при этом индексный файл должен постоянно отслеживать состояние основного файла. Этот процесс необходимый атрибут ведения базы данных. Но файлы располагаются раздельно,

17

и по этой причине возникают различные ситуации, при которых индексный файл перестает соответствовать основному файлу. В этой ситуации приходится старый индексный файл удалять с диска, а на его месте создавать новый индексный файл. Этот процесс называется переиндексацией.

Пример 121. Для файла STUDENTS.DAT, расположенном в корневом каталоге диска A создать индексный файл STUDENTS.NTX, соответствующий табл. 49.

Закрыть основной файл (процедура Close);

Ниже приведен код программы, обеспечивающей индексацию файла STUDENTS.DAT. Имя индексного файла формируется автоматически из имени основного файла. Файл размещается в том же директории, что и основной.

PROGRAM PR121;

TYPE STUDENT = RECORD

TAB : LONGINT;

FIO : STRING[20];

DATA : STRING[8];

GRUP : STRING[7]; STEPA: REAL END;

INDEX = RECORD

FIO : STRING[20];

NAMBER: INTEGER END;

VAR MS: ARRAY[0..20] OF STUDENT; MI: ARRAY[0..20] OF INDEX;L:INDEX; I, J, N: INTEGER; FS: FILE OF STUDENT; ST,STI: STRING; FI: FILE OF

INDEX;

BEGIN {ЧТЕНИЕ ФАЙЛА В МАССИВ MS}

WRITELN('ВВЕДИТЕ ИМЯ ИНДЕКСИРУЕМОГО ФАЙЛА: '); READLN(ST); ASSIGN (FS, ST); RESET(FS);

N := -1; {НОМЕР ЗАПИСИ В ФАЙЛЕ} WHILE NOT EOF(FS)

DO BEGIN N := N+1;

READ(FS, MS[N]) END;

CLOSE(FS);

IF N >- 1 THEN BEGIN

{ЗАПОЛНЕНИЕ МАССИВА ИНДЕКСОВ MI} FOR I:=0 TO N

DO BEGIN MI[I].FIO := MS[I].FIO; MI[I].NAMBER := I END; {СОРТИРОВКА ИНДЕКСНОГО МАССИВА ПО КЛЮЧЕВОМУ ПОЛЮ

FIO}

FOR I := 0 TO N

DO FOR J := N DOWNTO I + 1

DO IF MI[J-1].FIO > MI[J].FIO

18

THEN BEGIN

L := MI[J-1]; MI[J-1] := MI[J]; MI[J] := L END;

{ФОРМИРОВАНИЕ ИМЕНИ ИНДЕКСНОГО ФАЙЛА} IF POS('.',ST) = 0

THEN STI := ST + '.NTX'

ELSE STI := COPY(ST, 1, POS('.', ST)) + 'NTX'; {ФОРМИРОВАНИЕ ИНДЕКСНОГО ФАЙЛА} WRITELN('ЖДИТЕ ИДЕТ ИНДЕКСАЦИЯ ФАЙЛА ...', STI); ASSIGN(FI, STI); REWRITE(FI);

FOR I := 0 TO N

DO WRITE(FI, MI[I]); CLOSE(FI)

END

ELSE WRITE ('ФАЙЛ ',ST, ' НЕ СОДЕРЖИТ НИ ОДНОЙ ЗАПИСИ!') END.

11.6. Работа с файлом произвольного доступа

Рассмотрим четыре важнейших режима работы с файлом прямого доступа: просмотр информации в файле; редактирование содержимого полей, существующих в файле записей; корректировку структуры файла, с сохранением информации; удаление записей; добавление новой записи.

Просмотр файла

Доступ к компонентам файла произвольного доступа может быть как последовательный, так и произвольный. Но при этом мы просматриваем записи в том порядке как они располагаются на диске в основном файле. Часто этот порядок нас не устраивает. Например хочется вывести сведения о студентах в алфавитном порядке их фамилий, или по группам, а в каждой группе упорядочить по фамилиям. Именно для этих целей и используются индексные файлы и процедура Seek.

Приведем порядок действий при просмотре файла произвольного доступа: Присвоить файлу имя (процедура Assign);

Открыть файл (процедура Reset) и запросить индексный файл; Присвоить индексному файлу имя (процедура Assign); Открыть индексный файл (процедура Reset);

Осуществить последовательный просмотр индексного файла начиная с первой записи до метки EOF, выполняя для каждой записи следующие два пункта.

Для каждой записи индексного файла, используя процедуру Seek установить указатель основного файла на соответствующую запись;

Считать нужный компонент (оператор read) основного файла и вывести на экран монитора;

Закрыть файлы (процедура Close).

Пример 122. Вывести на экран монитора в алфавитном порядке фамилий сведения о студентах, хранящихся в файле STUDENTS.DAT, расположенном в корневом каталоге диска A.

19

Именно для решения таких задач и создаются индексные файлы. В нашем случае будем использовать индексный файл STUDENTS.NTX.

PROGRAM PR122;

TYPE STUDENT = RECORD

TAB : LONGINT;

FIO : STRING[20];

DATA : STRING[8];

GRUP : STRING[7]; STEPA: REAL END;

INDEX = RECORD

FIO : STRING[20];

NAMBER: INTEGER END;

VAR L: INDEX; S: STUDENT; I, J, N: INTEGER;

FS: FILE OF STUDENT; ST, STI: STRING; FI: FILE OF INDEX; BEGIN {ЧТЕНИЕ ФАЙЛА В МАССИВ MS} WRITELN('ВВЕДИТЕ ИМЯ ОСНОВНОГО ФАЙЛА: '); READLN(ST); ASSIGN (FS, ST); RESET(FS);

WRITELN('ВВЕДИТЕ ИМЯ ИНДЕКСНОГО ФАЙЛА: '); READLN(STI); ASSIGN (FI, STI); RESET(FI);

WHILE NOT EOF(FI) {ПРОСМОТР ИНДЕКСНОГО ФАЙЛА} DO BEGIN

READ(FI, L); SEEK(FS, L.NAMBER); READ(FS, S);

WRITELN(S.TAB: 9, S.FIO: 15, S.DATA: 10, S.GRUP: 9 , S.STEPA: 9: 2) END;

CLOSE(FS); CLOSE(FI); END.

Редактирование записей

Одной из наиболее часто встречающихся задач, является редактирование записей основного набора данных. Например, Вахрушеву лишили стипендии. Для поиска записи используется индексный файл. Проблема возникает в том случае, если приходится изменить значение ключевого поля, которое является основой индексного файла. В этом случае по окончании редактирования записи основного файла следует внести изменения в индексный файл. Например, студентка с фамилией Вейнерман вышла замуж за студента Яковлева и изменила свою фамилию на Яковлеву. Одним из простейших способов решения этой проблемы является переиндексация. То есть повторное создание индексного файла. Это самый долгий по времени, но и самый надежный способ. Остальные способы мы рассматривать не будем, так это прерогатива специальных разделов информатики, а именно разработки программного обеспечения СУБД.

Пример 123. Вывести на экран монитора с целью коррекции информацию о студенте из файла STUDENTS.DAT, расположенном в корневом каталоге диска A. Поиск

20

студента осуществить по его фамилии. Откорректировать любое из полей или все поля записи, и сохранить изменения в файле STUDENTS.DAT.

Алгоритм функционирования программы следующий: Присвоить основному файлу имя (процедура Assign);

Открыть уже существующий на диске основной файл (процедура Reset); Присвоить индексному файлу имя (процедура Assign);

Открыть уже существующий на диске индексный файл (процедура Reset);

Ввести с клавиатуры имя студента сведения о котором вы хотите посмотреть и возможно откорректировать.

Читать индексный файл запись за записью пока не будет достигнута метка EOF, сверяя имя студента с указанным. При совпадении организовать диалог для коррекции информации.

Скорректированную запись занести в соответствующую компоненту рабочего

файла.

Если при коррекции было изменено ключевое поле, установить флаг FL в состояние TRUE.

Закрыть основной файл (процедура Close); Закрыть индексный файл (процедура Close);

Если ключевое поле изменялось (анализ FL), то сделать переиндексацию.

Код программы приведен ниже. В программе сформирована процедура IND, которая обеспечивает переиндексацию файла в случае изменения ключевого поля FIO.

PROGRAM PR123;

TYPE STUDENT = RECORD TAB : LONGINT;

FIO : STRING[20];

DATA : STRING[8];

GRUP : STRING[7]; STEPA: REAL END;

INDEX = RECORD

FIO : STRING[20];

NAMBER: INTEGER END;

VAR L: INDEX; I, J, N: INTEGER; ST, STI: STRING; STUD: STRING[20]; S: STUDENT; FS: FILE OF STUDENT; FI: FILE OF INDEX;

FL: BOOLEAN; {ФЛАГ: TRUE - ИЗМЕНИЛОСЬ КЛЮЧЕВОЕ ПОЛЕ} PROCEDURE IND; {ПРЕРИНДЕКСАЦИЯ ФАЙЛА}

VAR MS: ARRAY[0..20] OF STUDENT;MI: ARRAY[0..20] OF INDEX; BEGIN {ЧТЕНИЕ ФАЙЛА В МАССИВ MS}

ASSIGN (FS, ST); RESET(FS);

N := -1; {НОМЕР ЗАПИСИ В ОСНОВНОМ ФАЙЛЕ} WHILE NOT EOF(FS)

DO BEGIN

N:=N+1; READ(FS, MS[N])