Страница 32 из 41
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 'очистка буфера
|