Справочник программиста на персональном компьютере фирмы 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                             'очистка буфера