Основные типы файлов в системе QBasic
Система QBasic поддерживает работу с файлами трех типов — строковыми, записеориентированными и двоичными. Приведенные термины не являются общеупотребительными, однако они достаточно точно отражают формат хранения данных в дисковых файлах.
Строковые файлы в системе QBasic
В строковом файле условной порцией хранения данных является строка переменной длины, завершаемая двумя управляющими байтами с кодами OD ("возврат каретки") и OA ("перевод строки"). Строка файла может быть либо пустой, либо содержать одно или несколько числовых и символьных значений. Символьное значение либо завершается запятой, либо заключается в двойные кавычки. Числовые значения представлены в символьном формате и завершаются либо запятой, либо пробелом. Последнее значение в файловой строке завершается парой управляющих кодов ODOA.
Строковый файл последовательного доступа для вывода открывается с помощью следующего оператора:
OPEN имя_файла FOR OUTPUT AS #k
Если мы собираемся добавлять информацию в уже существующий строковый файл, то его открывают с указанием FOR APPEND. Файл, из которого информация должна считываться, открывается с указанием FOR INPUT.
Открываемому файлу программист присваивает числовой номер к из диапазона [1,255], который впоследствии заменяет имя файла в операторах ввода (INPUT) или вывода (PRINT, WRITE). Символ tt может опускаться.
Закрывается строковый файл оператором CLOSE tk.
Вывод в строковый файл, как правило, осуществляется по оператору WRITE Ik. При таком выводе каждое текстовое значение автоматически заключается в кавычки и все данные разделяются запятыми. Чтение данных из строкового файла производится с помощью оператора INPUT #k и ничем принципиально не отличается от ввода данных из строки, набираемой пользователем на клавиатуре.
В принципе, в строковый файл можно произвести запись и по оператору PRINT#k. Однако при этом выводимый текст в кавычки не заключается и разделительные запятые между отдельными значениями не вставляются. Если в строке файла оказывается несколько текстовых и числовых значений, то их потом будет трудно извлечь. Коллизии подобного рода демонстрирует программа 7_01.bas.
Программа 7_01.bas
CLS : DEFINT A-Z: А$="Строка" OPEN "bas_txt"
FOR OUTPUT AS #1 FOR J=l TO 10
PRINT #1,A$;J,J*2
PRINT A$;J,J*2
NEXT J
CLOSE #1
OPEN "bas_txt"
FOR INPUT AS #2
FOR J=l TO 10
INPUT #2,B$,K1,K2
PRINT B$;K1,K2
NEXT J
CLOSE #2
END
Если ограничиться только первой половиной программы, которая записывает в дисковый файл bas_txt 10 строк и попутно выдает на экран содержимое этих строк, то кажется, что все в порядке. Содержимое файла bas_txt, которое можно увидеть, нажав клавишу F3, в точности повторяет ту информацию, которая отражена на экране:
Строка 1 2
Строка 2 4
Строка 3 6
Строка 4 8
Строка 5 10
Строка 6 12
Строка 7 14
Строка 8 16
Строка 9 18
Строка 10 20
Один пробел после слова строка образовался потому, что в теле оператора PRINT разделитель "точка с запятой" после текста не изменяет текущую позицию выводной строки, но записываемые числа положительны и вместо знака "+" мы видим пробел. Вторые числа в каждой строке начинаются с 15-й позиции (там тоже находится пробел вместо знака "+"). Этот переход в начало очередной зоны вывода вызван разделителем "запятая" в списке оператора PRINT. Если переключиться в режим просмотра шестнадцатеричной информации (F3 -> F4), то можно заметить дополнительные детали: однозначные числа представлены однобайтовыми кодами ASCII (1 -> 31, 2 -> —> 32, ...), а двузначные — двухбайтовыми (10 —> 3130, 12 -> 3132, ...). Кроме того, каждая строка завершается двухбайтовым признаком конца строки -ODOA. Это означает, что при выводе числовые данные были переведены в символьный формат, а каждая порция вывода была дополнена управляющими кодами Возврат каретки + Перевод строки.
Действие второй половины программы вызывает недоумение. Во-первых, на экране появляется сообщение input paste end of file, которое свидетельствует о попытке чтения после исчерпания данных в файле. Во-вторых, переключившись на экран пользователя, вместо ожидавшихся строк с одним словом и двумя числами в каждой мы видим совсем не то:
Строка1 2 0 2
4 0 3
6 0 4
..............
Тем не менее все объясняется достаточно просто. При считывании самой первой порции в переменную в$ заносятся первые 16 символов из строки дискового файла, завершаемые признаком конца строки (BASIC-система не настолько умна, чтобы остановиться после извлечения первых шести символов). При этом управляющие байты ODOA в переменную в$ не записываются, но пропускаются. Для формирования значения числовой переменной KI данные начинают извлекаться уже из второй строки дискового файла. Но там до первого разделителя числовых значений (пробела) расположены только нечисловые символы (слово Строка), которые игнорируются, и в переменную KI ничего не поступает (KI = о). В переменную К2 попадает первое числовое значение из второй строки (к2 = 2). При следующем повторении цикла в переменную в$ заносится остаток второй файловой строки, но лидирующие пробелы при этом игнорируются (в$ = "4"). Таким образом, к десятому повторению цикла образуется недостача одного числового значения.
Однако из приведенного примера вы должны сделать правильный вывод -нельзя просто так, без всяких разделителей, смешивать в одной строке символьные и числовые данные.
На самом деле, описанные выше проблемы снимаются, если в дисковый файл числовые и символьные данные выводятся по оператору WRITE #k. Проделайте эксперимент с программой 7_02.bas и поинтересуйтесь содержимым дискового файла bas_txt:
Программа 7_02.bas
CLS : А$ = "Строка"
OPEN "bas_txt" FOR OUTPUT AS #1
FOR J%=1 TO 10
WRITE #1,A$,J%,SQR(J%)
PRINT A$,J%,SQR(J%) NEXT J%
CLOSE #1
OPEN "bas_txt"
FOR INPUT AS #2
FOR J%=1 TO 10
INPUT #2,B$,I%,R
PRINT B$,I%,R NEXT j% CLOSE #2
END
Записеориентированные файлы в системе QBasic
Единицей обмена информацией для записеориентированных файлов является "запись", представляющая собой заранее описанную последовательность полей жесткой структуры. На каждом из таких полей располагается одно значение соответствующего типа в машинном формате. Последнее позволяет экономить место, необходимое для хранения данных, и исключает затраты на прямое или обратное преобразование данных между машинным представлением и символьным форматом в процессе обмена. Фиксированный размер каждого поля делает ненужным использование различных разделителей.
Описание структуры записи располагается между служебными словами TYPE — END TYPE. В профамме 7_03.bas через qq обозначено наименование шаблона записи, состоящей из трех полей с именами а (6-байтовое символьное поле), п (2-байтовое поле для хранения короткого числа) и г (4-байтовое поле для хранения короткого вещественного числа). С помощью оператора DIM объявлена структурированная переменная ь типа qq, содержащая три поля с именами b.а, b.n и b.r. Каждому из этих полей можно присвоить соответствующее значение и вывести запись ь в дисковый файл:
PUT #l,,b 'Вывод значения b в текущую запись
PUT #l,5,b 'Вывод значения b в запись с номером 5
Отсчет записей в файле ведется от 1. Поскольку имеется возможность вывести значение структуры в любое место записеориентированного файла, то его инициализация производится следующим образом:
OPEN "bas_rec" FOR RANDOM AS #1 LEN=12
Последнее указание (LEN=12) задает длину записи в байтах, и естественно, что она должна быть равна суммарной длине всех полей структур, участвующих в обмене.
Программа 7_03.bas формирует в цикле значения полей записи ь и выводит их на диск последовательно, а затем в цикле считывает эти записи в обратном порядке, демонстрируя тем самым произвольный доступ к записям.
Программа 7_03.bas
CLS TYPE qq
a AS STRING *6
n AS INTEGER
r AS SINGLE END TYPE DIM b AS qq b.а="Строка"
OPEN "bas_rec" FOR RANDOM AS §1 LEN=12
FOR J%=1 TO 10
b.n=J% : b.r=SQR(J%)
PUT #l,,b
PRINT b.a,b.n,b.r NEXT J% CLOSE #1
OPEN "bas_rec" FOR RANDOM AS #1
FOR J%=10 TO 1 STEP -1
GET #l,J%,b
PRINT b.a,b.n,b.r
NEXT J%
CLOSE #1
END
Двоичные файлы в системе QBasic
В двоичных файлах может храниться информация любого происхождения и рассматривается она только как последовательность байтов, пронумерованная от 1. Открываются двоичные файлы следующим образом:
OPEN имя_файла FOR BINARY AS #k
Доступ к данным в двоичном файле производится с помощью операторов PUT (вывод в файл) и GET (чтение из файла). При этом второй параметр в этих операторах обозначает номер байта дискового файла, с которого начинается обмен. Количество байтов, участвующих в обмене, определяется длиной третьего аргумента. С двоичным файлом можно работать, используя как последовательный (второй аргумент в операторах GET/PUT опущен), так и прямой (произвольный) доступ.
Программа 7_04.bas формирует в цикле и последовательно записывает в двоичный файл текст "строка", целочисленное значение счетчика цикла j%
и вещественное значение квадратного корня из j%, а затем в цикле считывает эти данные в обратном порядке.
Программа 7_04.bas
CLS : А$="Строка"
OPEN "bas_bin" FOR BINARY AS #1
FOR J%=1 TO 10
B=SQR(J%)
PUT #1,,A$: PUT #1,,J% : PUT #1,,B
PRINT A$, J%, В NEXT J% CLOSE #1 PRINT
OPEN "bas_bin" FOR BINARY AS #1
FOR J%=10 TO 1 STEP -1
GET #1,(J%-1)*12+1,A$
GET #1,(J%-1)*12+7,K%
GET #1,(J%-1)*12+9,B
PRINT A$,K%,B
NEXT J%
CLOSE #1
END