Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учебник_Попов_1.doc
Скачиваний:
6
Добавлен:
25.04.2019
Размер:
668.16 Кб
Скачать

2.11. Работа с дисковыми файлами

В случаях, когда на компьютере обрабатываются большие наборы данных, или данные должны быть сохранены после завершения программы, следует сохранять их в дисковых файлах. Для описания структуры файла введем следую­щие термины. Каждый файл состоит из одной или нескольких записей. Каждая запись, в свою очередь содержит поля данных. Обычно, файл органи­зуется так, что все его записи имеют одинаковую структуру. Если сравнить файл с таблицей, то строка таблицы соответствует записи, а отдельная клетка – полю. Например, пусть это файл о кадровом составе подразделения, где для каждого сотрудника хранятся данные: фамилия, табельный номер, год рождения, зарплата (в тыс. руб.).

поле 1

Фамилия

поле 2

Табель

поле 3

Год рождения

поле 4

Зарплата

Петров А.В.

870

1946

800

запись 1

Кулик С.П.

45

1970

1200

запись 2

. . .

Яшин А.А.

24

1972

950

запись N

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

Различают файлы с последовательным и прямым (произвольным) доступом. Простейшим является последовательный доступ. В этом случае программа обра­батывает файл целиком даже если нужно изменить только один единственный символ. Такой файл может быть одновременно использован только для одной из целей – запись или считывание информации. Структура данных в файле может быть нерегулярной – длины одноименных полей могут отличаться друг от друга в разных записях. В файлах с произвольным доступом программа может обращаться к любой записи по номеру для ее обработки. Последовательность доступа к записям может быть любой, например, можно перемещаться и в обратном порядке. Структуры всех записей в файле должны быть строго идентичны.

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

Любому действию с файлом должно предшествовать его открытие следующим оператором

OPEN имя_файла [FOR тип] AS#номер_файла LEN длина

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

Остальные параметры имеют следующий смысл:

тип – может иметь одно из значений, определяющих тип доступа:

OUTPUT – последовательный ввод данных в файл,

INPUT – последовательный вывод данных из файла.

APPEND – последовательный ввод с добавлением данных в конец файла.

RANDOM – прямой ввод-вывод данных. Если параметр тип не задан, подразумевается файл с прямым доступом (RANDOM).

длина – длина записи. По умолчанию равна 128 байт для файлов прямого доступа и 512 байт для файлов прямого доступа.

Примеры организации доступа к файлу KADR.DAT:

OPEN "kadr.dat" FOR OUTPUT AS#1 – запись в начало нового файла

(номер 1) с последовательным доступом

OPEN "kadr.dat" FOR APPEND AS#2 – запись (добавление) в конец

существующего файла с последовательным доступом

OPEN "kadr.dat" FOR INPUT AS#3 – чтение с начала существующего

файла с последовательным доступом

OPEN "kadr.dat" FOR RANDOM AS#4 – запись или чтение файла с

произвольным доступом

Функция

LOC (номер_файла)

возвращает текущую позицию в открытом файле. Для файлов прямого дос­ту­па, возвращается номер записи, к которой было последнее обращение. Для файлов последовательного доступа – текущую байтовую позицию, деленную на 128.

Функция

EOF (номер_файла)

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

Функция

LOF (номер_файла)

возвращает размер открытого файла в байтах.

Оператор

SEEK #номер_файла, позиция_в_файле

устанавливает указатель записей в заданную позицию. Для файлов прямого доступа – на запись с заданным номером. Для файлов с последовательным доступом – на байт с заданным номером от начала файла. В таких файлах оператор удобно использовать для перехода в его начало (например, SEEK #4,1 – переход в начало файла #4).

Оператор

CLOSE [[#номер_файла [,[#номер_файла]..]

закрывает файлы с перечисленными номерами. Если параметры отсутствуют, закрываются все файлы.

ФАЙЛЫ ПОСЛЕДОВАТЕЛЬНОГО ДОСТУПА. Работа с такими файлами осуществляется с помощью следующих операторов и функций.

Оператор

INPUT #номер_файла, переменные

читает данные из файла последовательного доступа в перечисленные пере­менные. Типы данных в файле и типы переменных должны соответствовать друг другу.

Оператор

WRITE #номер_файла [,список_выражений]

посылает данные из списка выражений в файл последовательного доступа.

Выводимые значения разделяются запятыми. Символьные строки заклю­чаются в кавычки.

Оператор

PRINT #номер_файла, [USING формат;] список_выражений[,/;]

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

Пример. Ввести в файл KADR.DAT данные о сотрудниках учреждения (фамилия, номер отдела, зарплата), первоначально хранимых в массивах fam$(n), ot(n), zar(n). Затем вывести из файла список сотрудников отдела 123, а также суммарную и среднюю зарплату его работников.

Программа подсчета суммарной и средней заработной платы отдела

n=6 'размерность исходных массивов данных (до 6 сотрудников)

'исходные массивы - фамилии, отделы, зарплаты

DIM fam$(n), ot(n), zar(n)

DATA "Иванов",123,800, "Петров",564,780, "Сидоров",123,950

DATA "Ильин",123,700, "Семина",564,600, "Коваль",123,900

READ fam$(1), ot(1), zar(1), fam$(2), ot(2), zar(2), fam$(3), ot(3), zar(3)

READ fam$(4), ot(4), zar(4), fam$(5), ot(5), zar(5), fam$(6), ot(6), zar(6)

'открытие файла KADR.DAT для ввода данных

OPEN "kadr.dat" FOR OUTPUT AS 1

PRINT " Список сотрудников"

PRINT "ФИО Отдел Зарплата"

FOR i=1 TO n 'запись данных в файл из массивов

WRITE #1, fam$(i), ot(i), zar(i)

PRINT fam$(i), ot(i), zar(i)

NEXT

PRINT

CLOSE #1 'закрытие файла

OPEN "kadr.dat" FOR INPUT AS 1 'открытие файла для просмотра

sum = 0: k = 0 'переменные для суммы и числа работников в отделе

DO WHILE NOT EOF(1)

INPUT #1, f$, o, z 'считывание данных из файла

IF o=123 THEN 'для отдела 123

sum=sum+z 'суммируется зарплата

k=k+1 'число работников

PRINT f$,o,z 'вывод сведений о сотрудниках отдела

END IF

LOOP

CLOSE #1

'вывод суммарной зарплаты отдела

PRINT "Фонд зарплаты отдела="; sum

PRINT "Средняя зарплата="; sum/k

Результат работы программы:

Список сотрудников

ФИО Отдел Зарплата

Иванов 123 800

Петров 564 780

Сидоров 123 950

Ильин 123 700

Семина 564 600

Коваль 123 900

Иванов 123 800

Сидоров 123 950

Ильин 123 700

Коваль 123 900

Фонд зарплаты отдела= 3350

Средняя зарплата= 837.5

Пример. Данные из файла KADR.DAT отсортировать по номерам отделов и занести в файл OTDEL.DAT.

Программа сортировки данных из файла KADR.DAT

DIM no(20) 'массив для хранения номеров всех найденных отделов

'открытие файла KADR.DAT c номером 1 для просмотра

OPEN "kadr.dat" FOR INPUT AS 1

nn=0 'переменная для подсчета числа существующих отделов

DO WHILE NOT EOF(1) 'просмотр файла 1

INPUT #1, f$, o, z 'считывание данных

FOR i = 1 TO nn 'просмотр номеров уже найденных в файле отделов

'если такой отдел уже попадался, переход к следующей записи

IF no(i) = o THEN GOTO m:

NEXT

'если такой отдел в массиве не найден, он заносится в элемент no(nn)

nn=nn+1: no(nn)=o

m: LOOP

'сортировка номеров отделов по возрастанию

FOR i=1 TO nn-1: FOR j=i+1 TO nn

IF no(j)<no(i) THEN SWAP no(i),no(j)

NEXT j, i

KILL "otdel.dat"

'открытие файл OTDEL.DAT для добавления

OPEN "otdel.dat" FOR APPEND AS 2

FOR i = 1 TO nn 'просмотр номеров отделов в массиве NN

SEEK #1, 1 'переход в начало исходного файла KADR

DO WHILE NOT EOF(1) 'просмотр записей в файле KADR

INPUT #1,f$,o,z 'считывание данных из него

'если номера отделов в массиве и файле KADR совпадают,

'данные из файла KADR записываются в OTDEL

IF no(i)=o THEN WRITE #2, f$,o,z

LOOP

NEXT

CLOSE #2 'закрытие файла OTDEL.DAT

OPEN "otdel.dat" FOR INPUT AS 2 'открытие его для вывода

ot 'переменная для фиксации изменения номера отдела

DO WHILE NOT EOF(2) 'просмотр записей в файле

INPUT #2, f$,o,z 'считывание списка сотрудников

'Если это новый отдел, запоминается (в OT) и выводится его номер

IF ot<>o THEN PRINT " Отдел "; o: ot=o

PRINT f$,o,z 'вывод на экран списка сотрудников

LOOP

CLOSE 'закрытие всех файлов

Результат работы программы:

Отдел 123

Иванов 123 800

Сидоров 123 950

Ильин 123 700

Коваль 123 900

Отдел 564

Петров 564 780

Семина 564 600

ФАЙЛЫ ПРЯМОГО ДОСТУПА. Ввод/вывод данных в файл/из файла здесь осуществляется с помощью следующих операторов.

PUT номер_файла [,[номер_записи][,переменная]]

GET номер_файла [,[номер_записи][,переменная]]

Если опущен параметр номер записи, будет читаться следующая запись после последнего оператора PUT/GET или запись, указанная последним оператором SEEK.

Для организации перемещения данных удобно использовать так называе­мые комбинированные типы данных. Это сложный тип данных, определяемый пользователем с помощью операторов:

TYPE имя_типа

элемент AS тип

[элемент AS тип]

. . .

END TYPE

Здесь: имя типа – имя пользовательского типа данных

элемент – имя элемента пользовательского типа

тип – указатель типа данных языка (INTEGER, LONG, SINGLE, DOUBL, STRING). Тип STRING задается в форме STRING* число_знаков_в_переменной.

Пример. Положим, структура файла данных о сотрудниках некоторой организации состоит из двух полей: символьного поля фамилий длиной до 12 букв (STRING*12) и целочисленного поля зарплаты (INTEGER). После определения пользо­вательского типа SOTR можно указать конкретные переменные и массивы – здесь массив ORG(50) и переменная А.

Обращение к элементам такой структуры должно осуществляться по сос­тавному имени, включающему имя переменной и через точку – имя элемента структуры. Например, имя ORG(1).FAM указывает на первый элемент массива ORG типа FAM. Здесь же показаны операторы присваивания и печати.

TYPE sotr

fam AS STRING*12

zar AS INTEGER

END TYPE

DIM org(50) AS sotr, a AS sotr

org(1).fam="Петров": org(1).zar=900: a.fam="Петров": a.zar=900

PRINT org(1).fam, org(1).zar

PRINT a.fam; a.zar

Именно переменная пользовательского типа должна быть указана в операторах PUT и GET.

Пример. Рассмотрим технику работы с файлом прямого доступа. Поло­жим, следует повысить зарплату сотрудникам организации, получающим менее 850 руб. на определенный, задаваемый в момент просмотра данных, процент. Программа состоит из трех разделов. В первом – из массива S в файл KADR.DAT заносятся исходные данные. Во втором – просматриваются данные обо всех сотрудниках, получающих меньше 850. Каждому их них руководитель подразделения назначает (или не назначает) процент увеличения зарплаты. Если процент указан, предъявляется новая зарплата и, при нажатии любой клавиши, обработка данных продолжается. В третьем разделе программы на экран выводятся обновленные данные из файла.

Иванов N отдела: 123 Зарплата: 800

Укажите % повышение зарплаты =20 Будет – 960

Для продолжения нажмите любую клавишу

Программа работы с файлом прямого доступа

TYPE kadr 'определение пользовательского типа данных

fam AS STRING * 12 'фамилия

ot AS INTEGER 'N отдела

zar AS LONG 'зарплата

END TYPE

n=6 'число сотрудников

DIM s(n) AS kadr 'объявление массива записей для ввода

DIM w AS kadr 'комбинированная переменная для вывода

DATA "Иванов",123, 800, "Петров", 564, 780, "Сидоров", 123,950

DATA "Ильин", 123, 700, "Семина", 564, 600, "Коваль", 123,900

READ s(1).fam, s(1).ot, s(1).zar, s(2).fam, s(2).ot, s(2).zar

READ s(3).fam, s(3).ot, s(3).zar, s(4).fam, s(4).ot, s(4).zar

READ s(5).fam, s(5).ot, s(5).zar, s(6).fam, s(6).ot, s(6).zar

OPEN "kadr.dat" FOR RANDOM AS 1 'открытие файла KADR.DAT

FOR i=1 TO n 'просмотр и запись данных в файл из массива S

PRINT s(i).fam, s(i).ot, s(i).zar

PUT #1, i, s(i)

NEXT

FOR i = 1 TO n 'анализ данных в файле

GET #1,i,w 'чтение данных из файла в переменную W

IF w.zar<850 THEN 'если зарплата <850

CLS

LOCATE 6, 20'

'выводятся данные о сотруднике

PRINT w.fam;” N отдела:”; w.ot;” Зарплата:”; w.zar

LOCATE 8, 20'

'определяется процент увеличения зарплаты

INPUT "Укажите % повышение зарплаты =", x'

IF x > 0 THEN 'если процент задан

w.zar=INT(w.zar*(1+x/100)) 'вычисляется новая зарплата

LOCATE 8, 55'

PRINT "Будет -"; w.zar 'вывод новой зарплаты

LOCATE 12, 23'

PRINT "Для продолжения нажмите любую клавишу"

SLEEP' 'пауза для просмотра

PUT #1, i, w 'запоминание нового значения

END IF

END IF

NEXT

CLS 'просмотр новых данных

PRINT "Новые данные"

FOR i=1 TO n'

GET #1,i,w: PRINT w.fam, w.ot, w.zar'

NEXT

CLOSE

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

1.  Создать файл, содержащий сведения о количестве изделий, собран­ных рабочими завода за неделю. Каждая запись содержит поля: фамилия сборщика, количество изделий, собранных им ежедневно в течение пяти дней недели, т.е. в понедельник, вторник и т.д.

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

2.  Создать файл, содержащий сведения о телефонных абонентах. Каждая запись имеет поля: фамилия абонента, номер телефона, год установки.

 Написать программу, выдающую:

– по вводимой фамилии абонента сообщается номер его телефона;

– определяется количество установленных телефонов с любого, вводимого с терминала, года.

3.  Создать файл, содержащий сведения о сдаче студентами сессии. Структура записи: номер группы, фамилия студента, оценки по четырем экзаменам и трем зачетам в форме "з" (зачет) и "н" (незачет).

 Написать программу, выдающую:

– фамилии неуспевающих студентов с указанием номера группы и числа задолженностей;

– средний балл каждого студента и группы в целом.