Справочник программиста на персональном компьютере фирмы IBM. Дисковые накопители - Запись в последовательные файлы
ОГЛАВЛЕНИЕ
5.4.3 Запись в последовательные файлы.
С точки зрения программиста языки высокого уровня работают с
последовательными файлами порциями в одну единицу данных. Один
оператор "записывает" содержимое переменной в последовательный
файл, ограничивая ее парой возврат каретки/перевод строки. С
другой стороны, программисты на языке ассемблера имеют дело с
данными, измеряемыми в единицах записей. Они помещают данные в
буфер, который может содержать одну или несколько записей, добав-
ляя пары возврат каретки/перевод строки между элементами данных,
а не между записями. Некоторые элементы данных могут принадлежать
двум записям. Тогда для записи используется функция MS DOS, поз-
воляющая записать на диск одну или несколько записей. На всех
уровнях программирования DOS может не производить физической
записи на диск каждый раз, когда была подана команда вывода.
Вместо этого, в целях экономии, DOS ожидает пока его выходной
буфер будет заполнен, прежде чем записать данные на диск.
Отметим, что Бейсик автоматически добавляет в конец записывае-
мого им последовательного файла символ с кодом ASCII 26 (Ctrl-Z).
Это требование стандартных текстовых файлов. Функции DOS не до-
бавляют этот символ; Ваша программа должна сама записать его в
конец элемента данных. Файлы прямого доступа не ограничиваются
символом ASCII 26.
Высокий уровень.
Бейсик готовит файлы к последовательной записи, открывая файл
в режиме последовательного доступа оператором OPEN. Этот оператор
имеет две формы и какую из них Вы выбираете это дело вкуса. Фор-
маты этого оператора такие:
100 OPEN "MYFILE" FOR OUTPUT AS #1
или
100 OPEN "O", #1, "MYFILE"
Во второй форме буква "O" обозначает вывод (output). Символ #1
обозначает кодовый номер, по которому Вы будете впоследствии
обращаться к файлу в операторах доступа, таких как WRITE #1 или
INPUT #1. В обоих случаях открывается файл с именем MYFILE для
приема данных в последовательном режиме. Если файл с таким именем
не найден на диске, то оператор OPEN создаст его. Если же такой
файл существует, то он будет перезаписан, т.е. после его закрытия
он будет содержать только новые записанные в него данные. Чтобы
добавить данные в конец существующего последовательного файла, не
изменяя его предыдущего содержимого, нужно открыть его, используя
первую форму оператора OPEN в виде OPEN "MYFILE" FOR APPEND AS
#1. Более подробно об этом см. [5.3.3].
Данные записываются в файл с помощью операторов PRINT# и WRI-
TE#. Они имеют одинаковую форму:
100 PRINT #1, S$
или
100 WRITE #1, X
#1 относится к идентификационному номеру файла (дескриптору фай-
ла), присваиваемому ему оператором OPEN. В первом примере в файл
записывается значение строковой переменной, а во втором численное
значение, но можно любым из них записывать и то и другое. Числен-
ные значения записываются в последовательные файлы в строковом
виде, хотя они и берутся не из строковых переменных. Например,
232 является 2-хбайтным целым в строковой форме, однако если X =
232, то оператор PRINT #1, X помещает в файл три байта, используя
коды ASCII для цифр 2, 3 и 2.
Операторы PRINT# и WRITE# отличаются способом отделения эле-
ментов данных в файле. Какой из них более подходящий определяется
характеристиками данных. Основное различие между двумя оператора-
ми состоит в том, что WRITE# вставляет дополнительные ограничите-
ли между элементами данных. Рассмотрим случай, когда оператор
выводит несколько переменных в виде 100 PRINT #1, A$, Z, B$ или
100 WRITE #1, A$, Z, B$. В этом случае пара возврат каретки/пере-
вод строки будет помещена в файл только за последней из трех
переменных (отметим, что строковые и числовые переменные могут
быть перемешаны). Как же можно впоследствии выделить эти три
переменные? Если был использован оператор PRINT#, то никак. Все
три переменные будут объединены в непрерывную строку. Если же был
использован оператор WRITE#, то каждый элемент данных будет зак-
лючен в кавычки, а между ними будут стоять запятые. Затем, при
чтении этих элементов из файла, Бейсик будет автоматически уда-
лять кавычки и запятые, которые были добавлены оператором WRITE#.
Имеется еще ряд менее важных вопросов. Один из них состоит в
том, что вся проблема с ограничителями может быть снята, если
использовать для вывода каждой переменной отдельный оператор
PRINT# или WRITE#. В этом случае PRINT# будет отделять все эле-
менты парами возврат каретки/перевод строки, а WRITE# будет де-
лать то же самое, но по-прежнему каждый элемент будет заключен в
кавычки (что напрасно расходует файловое пространство). Более
того, для вывода строк, которые сами содержат кавычки, оператор
WRITE# использовать нельзя, поскольку первая же внутренняя кавыч-
ка будет при чтении ошибочно воспринята как признак конца пере-
менной. И, наконец, отметим, что когда в одном операторе выводит-
ся несколько переменных, то оба оператора форматируют данные в
точности так же, как они форматировались бы при выводе на терми-
нал. Таким образом PRINT #1, A$, B$ отделяет B$ от A$, в то время
как PRINT #1, A$; B$ - нет; файл будет добавляться нужным числом
пробелов. Оператор PRINT# может быть испоьзован в форме PRINT #1
USING..., где могут быть использованы все обычные экранные форма-
ты PRINT USING для форматирования вывода в файл.
Вообще говоря, более экономично использовать оператор PRINT#,
записывая каждый раз по одной переменной. Этот метод избавляет от
излишних ограничителей и позволяет затем безошибочно считывать
строки любого вида. Более сложные схемы ограничителей, используе-
мые при записи нескольких переменных одним оператором PRINT# или
WRITE# могут привести к проблемам, особенно если одна переменная
будет считана как две, что приведет к потере текущей позиции в
файле.
После того как все данные будут записаны в файл, просто зак-
ройте его, чтобы обезопасить содержащиеся в нем данные. Напишите
CLOSE, чтобы закрыть все открытые файлы, CLOSE #1 - чтобы закрыть
файл #1 и CLOSE #1, #3 - чтобы закрыть файлы #1 и #3. Хотя в
некоторых случаях Бейсик прощает незакрытые файлы, но это не тот
случай. Операторы WRITE# и PRINT# выводят данные в файловый бу-
фер, который записывается на диск только тогда, когда они запол-
нены информацией. Последние введенные данные записываются на диск
оператором CLOSE. Отсутствие этого оператора может привести к
потере данных. Вот пример:
100 OPEN "A:NEWSEQ" FOR OUTPUT AS #1 'открываем файл
110 A$ = "aaaaa" 'готовим три строки
120 B$ = "bbbbb" '
130 C$ = "ccccc" '
140 WRITE #1, A$, B$, C$ 'запись строк
150 CLOSE 'очистка буфера