[<>] ~~TOC wide~~ ====== Глава IX. Файловые средства MSX BASIC ====== \\ //Файл// (от англ. file — досье, картотека), набор данных,— \\ 1) совокупность упорядоченных и взаимосвязанных записей, имеющая описание для идентификации отдельных записей; \\ 2) последовательность записей, размещаемая на внешних запоминающих устройствах (внешней памяти) и рассматриваемая в процессе пересылки и обработки как единое целое. —//Математический Энциклопедический Словарь// В персональных компьютерах [[msx:yamaha_kuvt:yamaha_kuvt|]] предусмотрена работа с двумя версиями языка BASIC: [[msx:basic:]] и [[msx:disk_basic]]. Версия языка [[msx:basic:]] предусматривает работу только с накопителем на магнитной ленте, а в версии [[msx:disk_basic]] возможно работать как с накопителем на магнитной ленте, так и с магнитными дисками. Выбор версии языка BASIC, с которой будет работать персональный компьютер [[msx:yamaha_kuvt:yamaha_kuvt|]], осуществляется автоматически и зависит от состава подключённых внешних устройств хранения информации. Версия языка [[msx:basic:]] "прошита" (записана, хранится) непосредственно в ПЗУ компьютера, а версия языка [[msx:disk_basic]] записана и хранится в ПЗУ интерфейса (устройства сопряжения и согласования) дискового накопителя — //дисковода//. В зависимости от того, подключён ли интерфейс (вместе с дисководом) к компьютеру или нет, и выбирается версия языка BASIC, с которой мы будем работать. Если интерфейс подключён, то при включении компьютера "работает" интерпретатор языка [[msx:disk_basic]], а если нет, то "включается" интерпретатор языка [[msx:basic:]]. Практически для учительского компьютера это делается следующим образом: нажмите кнопку Reset и в момент начальной инициализации компьютера держите нажатой клавишу SHIFT ! Будем предполагать, что Ваш компьютер имеет встроенный дисковод. В таком варианте при включении запускается [[msx:disk_basic]], а приоритетным устройством внешней памяти является дисковод ''А:''. Работая на компьютере без дисковода, Вы запускаете при включении [[msx:basic:]], а приоритетным устройством является кассетный магнитофон (''CAS:''), имя которого может опускаться. //Замечание//. \\ В СССР распространены две версии языка [[msx:basic:]]: * [[msx:basic:#v1x|версия 1.0]] — на компьютерах серии [[msx:msx_1]]: * [[msx:yamaha_yis-503iir:yamaha_yis-503iir|]] * [[msx:basic:#v2x|версия 2.1]] — на компьютерах серии [[msx:msx_2]]: * [[msx:yamaha_yis-503iiir:yamaha_yis-503iiir|]] * [[msx:yamaha_yis-805-128r2:yamaha_yis-805-128r2|]] Для определения номера версии в Вашей программе проверьте содержимое ячейки ПЗУ с адресом &H002D: ? PEEK(&H2D) ^ Номер версии ^ Содержимое ячейки ^ | 1.0 | 0 | | 2.1 | 1 | 8-) В настоящее время рекомендуется использовать [[msx:nextor:disk_basic|расширения Disk BASIC, реализованные в Nextor]] {{anchor:n91}} ===== IX.1. Работа с файлами на дискетах ===== Под словом //"данные"// мы будем подразумевать содержимое памяти компьютера. Принято различать текст программы, исходные данные для работы программы и результаты работы программы. Работа с внешней памятью подразумевает запись и чтение данных, размещаемых на внешних носителях информации — кассете магнитной ленты или гибком магнитном диске (//дискете//). {{anchor:n911}} ==== IX.1.1. Форматирование дискеты ==== Дискеты бывают следующих типов: - односторонние одинарной плотности (SS, SD); - односторонние двойной плотности (SS, DD); - двусторонние двойной плотности (DS, DD). Односторонность и двусторонность свидетельствует о том, имеет ли дисковод одну или две магнитные головки, которые обеспечивают запись и считывание информации с одной или двух сторон гибкого диска. Лучший способ объяснить понятие "плотность записи" — провести аналогию с грампластинкой: считать, например, что на диске двойной плотности в два раза больше "дорожек", чем на диске одинарной плотности. И хотя память на гибком диске является магнитной и никаких, естественно, дорожек нет, на гибком диске четверной плотности может храниться в четыре раза больше информации, чем на диске одинарной плотности. Для работы с 3,5–дюймовым (8,89 см) дисководом MSX–компьютера используются односторонние дискеты MF1–DD, двусторонние дискеты MF2–DD или их аналоги (слова: "диск", "дискета" и "флоппи–диск" мы будем рассматривать как синонимы). Дискета заключена в твёрдый пластмассовый конверт и имеет переключатель защиты записи и скользящую шторку для прикрытия окна, через которое организуется чтение (запись) информации. Вставлять дискету в карман (щель) дисковода и извлекать её оттуда можно лишь при //включённом// дисководе! {{anchor:mf2dd}} Приведём некоторые характеристики дискеты MF2–DD : |Ёмкость при записи|| |всего|720 Кбайт| |для файлов пользователя|713 Кбайт| |Плотность при записи|8717 бит/дюйм| |Среднее время доступа|95 мс| |Максимальное количество файлов|112| Разрешается подключать к компьютеру как одиночные, так и спаренные дисководы. В первом случае за устройством закрепляется переменное имя, которое в любой момент времени принимает одно из конкретных значений "А" или "В". Во втором случае основной дисковод получает имя "А", а дополнительный — "В". Везде ниже, если это не оговорено специально, изложение ориентировано на использование одного дисковода. {{anchor:callformat}} Для подготовки диска к работе с командами и функциями [[msx:disk_basic]] необходимо осуществить специальную разметку его поверхности, называемую //форматированием//. Для этого дискета вставляется в карман дисковода, и выполняется команда: CALL FORMAT или _FORMAT , которая вызывает на экране индикацию запроса: Drive name? (A,B) █ Ответом на него должен быть ввод одной из латинских букв А или В, в зависимости от имени устройства, в котором находится дискета. На появившийся второй запрос–"подсказку": 1 - Double sided 2 - Single sided ? █ пользователь обязан отреагировать вводом 1, если диск — двусторонний, или 2, если диск — односторонний. Далее по указанию: Strike a key when ready █ нажмите любую клавишу. После этого начинается процесс форматирования, то есть размещение на диске управляющих меток. При этом ранее имевшаяся там информация разрушается. Правильное завершение этого процесса вызывает индикацию сообщения Format complete Ok █ Форматирование //новых// дискет обязательно! Учтите, что именно проведённая разметка дискеты, а не её потенциальные возможности определяет объем информации, который она может хранить, и с каким дисководом её можно использовать! В заключении дадим несколько //полезных советов//: - В дискетах не предусмотрена идеальная защита записанных на них данных: защитные конверты рассчитаны только на предохранение поверхности носителей от повреждений на коротком пути от "дискотеки" до дисковода. \\ Особую осторожность надо соблюдать при нанесении надписей на наклейке, прикреплённой к дискете, так как даже давление карандаша или шариковой ручки может оказаться достаточным, чтобы через защитный конверт повредить магнитный слой дискеты. Во избежание порчи информации, записанной на дискетах, последние следует хранить подальше от телевизоров, видео–мониторов, телефонов и других источников магнитных полей; - Для защиты файлов, сохранённых на дискете, позаботьтесь о создании копий файлов на другой дискете или на магнитной ленте; - Создайте архив файлов программных текстов и снабжайте дискеты и магнитные ленты архива этикетками; - Защищайте Ваши программы от неосторожного обращения путём установки переключателя защиты от записи на дискете. {{anchor:n912}} ==== IX.1.2. Имена файлов ==== При создании на дискете нового файла ему необходимо присвоить определённое //имя//. Оно должно быть уникальным, то есть не совпадать ни с одним из уже имеющихся имён файлов, сформированных на данной дискете ранее. Имя служит для идентификации файлов и строится из последовательности символов алфавита [[msx:basic:]]. При этом должны учитываться следующие обстоятельства: - Количество символов имени не может превосходить 11. Попытка сформировать имя большей длины ни к чему не приводит. Правые лишние символы отбрасываются; - Соответствующие прописные и строчные латинские буквы, используемые в имени, равнозначны; соответствующие прописные и строчные буквы русского алфавита, используемые в имени, //неравнозначны//; - В имени не должно быть символов: ; , + " = [ ] * \ / ? пробел - Символ ":" используется только при задании составных имён для разделения их на две части, первая из которых есть имя устройства, а вторая — имя файла. В этом случае при записи файла на диск фиксируется лишь вторая часть имени; - Нельзя задавать имя, состоящее из одних пробелов или начинающееся с пробела; - Имя не должно начинаться с точки ("."). В нем не может быть более одного такого символа и более 8 символов перед ним (если их больше восьми, то после восьмого символа устанавливается "."). Кроме того, десятичной точкой имя можно разделить на две зоны: //корень// (до точки) и //расширение// (после точки). Расширение состоит не более чем из трёх символов. Номер начальной позиции корня — 1, а расширения — 10. Если пользователь фиксирует имя без расширения с количеством символов, большим 8, то компьютер автоматически разбивает его на корень и расширение, вставляя в требуемое место точку. Сообщение об ошибке "Bad file name" (//"Недопустимое имя файла"//) появляется в том случае, когда имя файла содержит более //восьми// символов перед явно указанным расширением; если же расширение состоит более чем из //трёх// символов, то интерпретатор игнорирует лишние символы. __//Примеры//__. ^ Имя, заданное пользователем ^ Представление имени в компьютере ^ | КАТАЛОГ|КАТАЛОГ | | LESSON.123|LESSON .123 | | BASIC|BASIC | | ВАЛ.процент|ВАЛ .про | | ПРОТИВОГАЗ |ПРОТИВОГ.АЗ | Общепринято, что расширение имени файла должно обозначать его тип. Обычно применяются следующие стандартные расширения имён: ^ Расширение ^ Комментарий ^ | .ASM |Исходная программа на языке ассемблера| | .BAK |Резервный файл или копия некоторого файла, сделанная на случай повреждения оригинала| | .BAS |Программа на языке BASIC| | .BAT |Командный файл для пакетной обработки| | .C |Исходная программа на языке C| | .COM |Команда или программа, пригодные для непосредственного исполнения под управлением DOS| | .DAT |Файл данных| | .DOC |Файл документов (для текстовой обработки)| | .FOR |Исходная программа на языке Фортран| | .LIB |Библиотека программ| | .OBJ |Скомпилированная объектная программа на машинном языке| | .PAS |Исходная программа на языке Паскаль| | .PIC |Данные выводимого на экран изображения| | .TMP |Временный файл| | .TXT |Текстовый файл| //Маленькая хитрость//. Оградить Ваш файл от посторонних взглядов можно, дав ему секретное имя AAAAAAAA.AAA например. Секрет здесь в том, что в этом имени часть букв A из русского, а часть — из латинского алфавита, и об этом знает только хозяин файла. В большинстве случаев желательно, чтобы присвоенные файлам имена были индивидуальными и единственными и точно указывали, какой именно файл имеется в виду. Но иногда удобнее обратиться сразу ко всей группе файлов, а не работать с ними по одному. Для указания //родовых// имён файлов могут использоваться специально предназначенные для этого знаки ? и *. //Вопросительный// знак является единственным неоднозначно интерпретированным символом в имени файла. Например, имена * MAX1.ASM * MAX2.ASM * MAX3.ASM все соответствуют родовому имени файла MAX?.ASM, но ему не соответствует имя MAX10.ASM. //Звёздочка// обозначает любое количество неоднозначно интерпретируемых символов. Например, Zilog*.A* будет обозначать любое имя файла, которое начинается с Zilog, при условии, что его расширение начинается с A. \\ Однако звёздочка имеет смысл только при использовании её в качестве последнего символа имени файла или расширения. Например, родовое имя файла *CALC.BAS — это то же самое, что и имя *.BAS, которое соответствует каждому файлу, имеющему расширение имени *.BAS. Отметим, что *.* — родовое имя файлов с любыми именами. {{anchor:autoexecbas}} === AUTOEXEC.BAS === Имя файла ''AUTOEXEC.BAS'' происходит от Automatic Execution ("автоматическое исполнение"). Файл с таким именем будет автоматически загружен и запущен. ''AUTOEXEC.BAS'' это Программа на языке BASIC, это файл можно использовать например, для выполнения инициализации (подготовки компьютера к работе). Подробно об этом процессе написано в разделе: [[007#n73|VII.3. Инициализация в языке MSX BASIC]]. Пример [[007#fk-bas|установки новых значений функциональных клавиш]] через {{.examples:autoexec.bas|}} \\ [[+tab|wmsxbpge>autoexec.bas]] ---- 8-) добавлено 2019-10-17 {{anchor:callsystem}} === CALL SYSTEM === Оператор ''CALL SYSTEM'' [[bibliography#b101|[101]]] Переход в ДОС: * [[msx:dos:|]] * [[msx:dos2:|]] * [[msx:nextor:|]] CALL SYSTEM Файл , где * ''CALL SYSTEM'' — Переход в ДОС * //Файл// — путь к файлу для выполнения, формат задаётся в соответствии с используемой ДОС. {{anchor:cmd}} === CMD === Оператор ''CMD'' [[bibliography#b101|[101]]] CMD Команда , где * ''CMD'' — зарезервированное слово. * //Команда// — команда для выполнения. Значение может быть любым, нужно задать этот параметр, иначе при выполнении оператора возникнет ошибка «Illegal function call». **Этот оператор не используется!** Вероятно, что оператор был сделал для запуска команд [[msx:dos:|]], но вместо него используется ''[[#callsystem|CALL SYSTEM]]''. {{anchor:attr}} === ATTR$() === Функция ''ATTR$()'' [[bibliography#b101|[101]]] **Эта функция не используется!** {{anchor:ipl}} === IPL === Оператор ''IPL'' [[bibliography#b101|[101]]] IPL Команда , где * ''IPL'' — зарезервированное слово * Команда — команда для выполнения. Значение может быть любым, нужно задать этот параметр, иначе при выполнении оператора возникнет ошибка «Illegal function call». **Этот оператор не используется!** IPL означает «Начальный загрузчик программ», но при разработке стандарта MSX функциональность была заменена на ''[[#autoexecbas|AUTOEXEC.BAS]]'', когда файловая система FAT была выбрана в качестве стандарта. {{anchor:n913}} ==== IX.1.3. Справочная информация о файлах ==== \\ Старейшим из дошедших до нас каталогов признается список литературных произведений на шумерской глиняной плитке, относящейся к 2000 г. до н.э.. —//А.Михайлов// {{anchor:files}} Сейчас мы расскажем вам о довольно простых средствах для получения списка имён файлов, размещённых на дискете (''FILES''), размера её свободной части (''[[#DSKF]]'') и некоторой другой справочной информации. Вывод имён файлов осуществляется по команде (оператору!) [L]FILES [I] , где: * ''FILES'', ''LFILES'' ("файлы") — служебные слова; * I — строковое выражение, значение которого определяет имя файла или родовое имя файлов. При выполнении этой команды без параметра I список имён всех файлов диска или отображается на экране (если префикс ''L'' отсутствует), или распечатывается принтером (префикс ''L'' есть). В зависимости от типа экрана и его ширины индикация имён организуется в несколько колонок. Вывод списка файлов на печать проводится в 1 колонку: каждому имени отводится одна строка. При отсутствии файлов на диске выдаётся сообщение: "File not found" (//"Файл не найден"//). Если параметр I указан и на диске имеется файл с этим именем, то данный факт подтверждается выводом единственного имени I (в противном случае Вы прочтёте неприятное сообщение: "File not found"). Для указания диска добавляется имя диска ''A:'', ''B:'', и т.д. При использовании [[msx:nextor:nextor|]] к команде можно добавить параметр ''L'' и команда может быть использована в таком виде: FILES "B:",L При использовании этого параметра список файлов выводиться в "длинном" формате, кроме имени/расширения выводится дата, размер и атрибуты файла. __//Примеры//__. FILES 100 FILES FILES "Игры" LFILES FILES "B:" {{anchor:dskf}} Функция ''DSKF()'': DSKF(n) , где: * ''DSKF''("DiSK Free" — "свободная часть диска") — служебное слово; * n — арифметическое выражение, целая часть значения которого должна принадлежать отрезку [0,8], возвращает размер в Килобайт свободной части диска. Целая часть значения n определяет имя диска: {{anchor:drive_number}} ^ Значение ^ Имя диска ^ | 0 | Текущий | | 1 | A | | 2 | B | | 3 | C | | 4 | D | | 5 | E | | 6 | F | | 7 | G | | 8 | H | __//Примеры//__. PRINT DSKF(0):PRINT DSKF(1):PRINT DSKF(2) X=1:PRINT DSKF(X) IF DSKF(0)>200 THEN 1000 Забегая далеко вперёд, заметим, что для определения размера в байтах области дискеты, отведённой под произвольный файл, можно воспользоваться командами: OPEN "Имя файла" FOR INPUT AS#1:PRINT LOF(1):CLOSE #1 {{anchor:disk_sectors}} === Работа с секторами диска === FIXME {{anchor:dski}} Функция ''DSKI$()'' [[bibliography#b101|[101]]] Эта функция считывает сектор (512 байт) диска. DSKI$(<Диск>,<Сектор>) , где: * ''DSKI$'' — служебное слово; * //Диск// — арифметическое выражение, целая часть значения которого должна принадлежать отрезку [0,8], целая часть значения n определяет имя диска смотри [[#drive_number|таблицу]] * ''Сектор'' — номер сектора диска от 0 до максимального значения 719 для односторонних дисков и 1439 для двусторонних дисков. Описание для [[msx:nextor:disk_basic|Nextor]]: [[msx:nextor:disk_basic#DSKI|DSKI$()]] {{anchor:dsko}} Функция ''DSKO$'' [[bibliography#b101|[101]]] Эта функция записывает сектор (512 байт) диска. DSKO$ <Диск>,<Сектор> , где: * ''DSKO$'' — служебное слово; * //Диск// — арифметическое выражение, целая часть значения которого должна принадлежать отрезку [0,8], целая часть значения n определяет имя диска смотри [[#drive_number|таблицу]] * ''Сектор'' — номер сектора диска от 0 до максимального значения 719 для односторонних дисков и 1439 для двусторонних дисков. Описание для [[msx:nextor:disk_basic|Nextor]]: [[msx:nextor:disk_basic#DSKO|DSKO$]] {{anchor:n914}} ==== IX.1.4. Операторы NAME, COPY и KILL ==== {{anchor:name}} Изменение имени программного файла или файла данных производится по команде (оператору) NAME I AS J , где: * ''NAME'' ("имя") — служебное слово, * I — строковое выражение, значение которого определяет "старое" имя файла, * J — строковое выражение, значение которого определяет "новое" имя файла. При выполнении этой команды прерывание происходит при отсутствии на дискете файла с именем I (нечего переименовывать!), при наличии на ней файла с именем J (имя J уже зарезервировано!) или при закрытой на запись дискете. В противном случае файл с именем I получает новое имя J. При задании имени J разрешено использование символов "?". Но при реальном формировании имени J на дискете каждый такой символ будет заменён на элемент из соответствующей позиции имени I. __//Примеры//__. NAME "алфавит" AS "АЛФ" name X$ as "X.1" 200 NAME "PQR.XYZ" AS "?.?11" В последнем случае новое имя будет выглядеть так: Р ▲ .Х11 │ 7 пробелов {{anchor:copy}} Для дублирования на дисках программных файлов и файлов данных применяется команда (оператор) COPY i TO j , где: * ''COPY'' ("копировать"), ''ТО'' ("в") — служебные слова; * i — строковое выражение, значение которого определяет имя исходного файла; * j — строковое выражение, значение которого определяет имя формируемого файла. При выполнении команды (оператора) ''COPY'' по файлу любого формата с именем i создаётся его копия с именем j. Имена i и j не должны совпадать. В том случае, когда файл с именем j уже существует на дискете, содержимое файла с именем j заменяется на содержимое файла с именем i и, естественно, "старое" содержимое файла с именем j пропадает! Если i или j — файлы данных, то они не должны быть открыты! __//Примеры//__. - COPY "AL" TO "LA" - COPY "X" TO "X.1" - 10 SAVE "U.1" 20 FOR J=1 TO 20 30 COPY"U.1"TO"U."+MID$(STR$(J),2) 40 NEXT - COPY "A:ПРОБА" ТО "В:ПРОБА" Копирование всех файлов с одной дискеты на другую при наличии нескольких (больше двух) дисководов проводится операторами: COPY "A:*.*" TO "B:*.*" (с А на В) COPY "B:*.*" TO "A:*.*" (с В на А) На одном дисководе эта процедура и ей подобные (см.пример 4) реализуются по соответствующим сообщениям на экране периодической сменой дискет в кармане дисковода. Если служебное слово ''ТО'' и второй аргумент будут опущены, то файл будет скопирован на активный дисковод (обычно с B: на A:), например: COPY"b:E87.COM" . {{anchor:kill}} По команде (оператору) KILL I , где: * ''KILL'' ("разрушать", "убивать") — служебное слово; * I — строковое выражение, значение которого определяет имя файла, происходит разрушение на дискете файла с именем I и увеличение на соответствующую величину размера свободной части дискеты. Фактическому разрушению (стиранию) подвергается лишь справочная информация о файле. Если I — имя файла данных, то при выполнении команды ''KILL'' он не должен быть открыт. __//Примеры//__: - KILL"Бочка":KILL"R.T" - X$="ЮюЮ":KILL X$ - 100 FOR K=1 TO 25:KILL"ЦЕХ."+MID$(STR$(K),2):NEXT {{anchor:n915}} ==== IX.1.5. Операторы LOAD, SAVE, RUN и MERGE ==== {{anchor:save}} По команде (оператору): SAVE I [,A] , где: * ''SAVE'' ("сохранить") — служебное слово; * I — строковое выражение, значение которого определяет имя файла, программа из оперативной памяти под именем I записывается на дискету. В зависимости от наличия или отсутствия параметра А запись проводится соответственно или в формате ASCII, или в форме внутреннего представления (см. [[202|]]). Попробуем прочесть программу 10 X=1 , записанную: * в кодах ASCII: 10 X=1 * во внутреннем представлении (по кодам, см. [[202|]]): FF 09 80 0A 00 58 EF 12 00 00 00 ── ───▲─── ───▲─── ── ▲ ── ─▲ ───▲─── Начало ▲ │ │ ▲ │ ▲ │ └ Конец программы ┘ Адрес следу– Номер └ X = 1 ┘ Конец программы ющей строки строки (10) строки Если данная программа впоследствии будет погружаться в память для слияния с другими программными модулями, то её необходимо записывать в коде ASCII. Заметим, что формат ASCII приводит к увеличению в несколько раз времени записи программ из оперативной памяти на дискету, а также их чтения с дискеты в память. К тому же для их размещения на дискете требуется приблизительно на 30% больше места, чем для соответствующих программ, написанных во внутреннем представлении (см. [[202|]]). При наличии на диске программного файла или файла данных с именем I и записи на него новой программы под тем же именем, старый файл пропадает и происходит изменение размера свободной части диска в соответствии с новыми размерами файла с именем I. __//Примеры//__: - - SAVE"PROTOOL.SYS" - X$="Z80.ABC":SAVE X$:SAVE"PRIMER.BAS",A - 10 FOR M=1 TO 30:SAVE"палата"+MID$(STR$(М),2):NEXT Для считывания программ с дискеты в оперативную память используются команды (операторы) ''[[#load|LOAD]]'' и ''[[#run|RUN]]''. {{anchor:load}} По команде LOAD I[,R] , где: * ''LOAD'' ("загрузка") — служебное слово; * I — строковое выражение, значение которого определяет имя файла; * R — необязательный параметр; прежде всего закрываются все файлы и оперативная память очищается от программ и данных. Далее программа, записанная на дискете в машинных кодах или формате ASCII под именем I, загружается в оперативную память. При наличии параметра R после загрузки производится запуск программы на счёт. __//Примеры//__: - LOAD"X.Y" - Z$=MID$(A$,5,3):LOAD Z$,R Ещё раз напомним Вам, что загрузка программы "стирает" программу, находящуюся в момент загрузки в памяти компьютера. По команде {{anchor:run}} RUN I[,R] , где: * ''RUN'' ("запуск", "прогон") - служебное слово, * I — строковое выражение, значение которого определяет имя файла, в оперативную память загружается и запускается на счёт программа, записанная на диске под именем I в машинных кодах или в формате ASCII. При отсутствии параметра R перед загрузкой файла с именем I закрываются все открытые файлы, и память очищается от программ и данных. При наличии параметра R из памяти удаляются программы и значения переменных. Однако файлы данных //не закрываются// ! {{anchor:e0915-01}} __//Пример//__[[bibliography#b5|[5]]]. \\ {{.examples:0915-01.bas|}} \\ [[+tab|wmsxbpge>0915-01.bas]] 1 'Меню многомодульного файла "MMF" 2 COLOR 1,7,13:SCREEN 1:PRINT:PRINT TAB(7)"Основное меню" 4 PRINT TAB(6)"───────────────":PRINT 6 PRINT"1. программа A - 1":PRINT"2. программа B - 2" 8 PRINT"3. программа С - 3":PRINT"4. программа Д - 4" 11 INPUT R:IF R<1 OR R>4 THEN 11 13 ON R GOTO 14,15,16,17 14 RUN"прог.А",R 15 RUN"прог.В",R 16 RUN"прог.С",R 17 RUN"прог.Д",R Приведём вид отдельного модуля, например модуля с именем "прог.А": 10 PRINT"Выполняется программа А" 20 RUN"ММF",R Интересные возможности по "соединению" программ предоставляются командой (оператором!) MERGE I , где: * ''MERGE'' ("слияние") — служебное слово; * I — строковое выражение, определяющее имя файла, записанного на дискете в формате ASCII. Выполнение команды ''MERGE'' начинается с закрытия всех файлов и чистки оперативной памяти от данных. Далее производится слияние программы А, находящейся в памяти, с программным файлом, записанным на диске в формате ASCII под именем I. __//Примеры//__: MERGE "TTT" L$="техника":MERGE L$ 100 MERGE "LIST.3" Обратите внимание на тот факт, что программы, вызываемые командой ''MERGE'', имеют более высокий приоритет, по сравнению с программами, находящимися в памяти компьютера. Поэтому если в объединяемых программах имеются строки с одинаковыми номерами, то строки программы в памяти компьютера будут заменены соответствующими строками "добавляемой" программы с именем I. Наиболее целесообразно использовать этот оператор при работе с библиотеками подпрограмм на магнитной ленте или на дискете. Покажем, как это делается. __//Пример//__. Предположим, что программа, находящаяся в памяти, занимает строки с 10 по 1290. Для добавления подпрограммы, названной при записи на дискету "ROUT1" и занимающей строки с 10 по 190, сначала Вы должны сохранить программу, находящуюся в памяти. После этого Вы вызываете подпрограмму "ROUT1", используя команды ''LOAD'' или ''CLOAD''. Теперь используйте команду ''RENUM'' для перенумерации строк подпрограммы, начиная, например, со строки 10000. Далее сохраните подпрограмму в формате ASCII, назвав её новым именем, например "ROUT0", после чего повторно загрузите основную программу. Теперь выполнение команды MERGE "ROUT0" приведёт к тому, что в конце текста основной программы будет добавлен текст подпрограммы с номерами строк, начинающимися с 10000. {{anchor:n92}} ===== IX.2. Файлы данных прямого доступа ===== \\ Я знаю, что положил это в надёжное место, но теперь не могу вспомнить, в какое именно! —//Из диалога на приёме у врача// Как мы уже отмечали (см. [[005|главу V]]), файл данных //прямого// доступа представляет собой последовательность нумерованных групп значений, называемых //записями//. Запись представляет собой единицу хранимой в файле информации. Размер записи зависит от решаемой Вами задачи. Запись есть совокупность сведений о некотором объекте. Она образуется из //полей//, или элементов данных, указывающих на различные атрибуты, присущие конкретному объёму. Так, если "объектами" для зубного врача являются пациенты, то каждая запись должна хранить информацию о каком–либо пациенте, а её полями могут быть имя пациента, его возраст, номер телефона и число поставленных пломб. На рисунке показано зрительное представление организации файла прямого доступа. Записи с данными хранятся на дискете. При каждом запросе программы на чтение или на запись должен быть указан //номер записи//, по которому во внутреннем справочнике находится её фактическое положение на дискете, что позволяет немедленно произвести чтение или запись. Таким образом осуществляется прямой доступ к записям, требующий примерно одного и того же небольшого (зависящего от скорости вращения дискеты) времени для всех записей. ┌──────────────────────────────┐ ┌──────────────────┐ │ ◀───▶ Запись с данными │ Запись │ Внутренний справочник файла, │ └──────────────────┘ ────▶────◀──┤ связывающий номер записи с │ … Чтение│её физическим местонахождением│ ┌──────────────────┐ │ ◀───▶ Запись с данными │ └──────────────────────────────┘ └──────────────────┘ Нумерация записей выполняется последовательно, начиная с нуля. В запись объединяются логически связанные между собой данные, и номер записи обычно связывается с этими данными естественным образом. Например, если записи содержат информацию о студентах некоторой группы, то в качестве номеров записей можно использовать номера студентов в списке группы. Во время выполнения операции //вывода// для размещения записи будет выбрано место, определяемое её номером. При выполнении операции ввода по номеру отыскивается запись и передаётся в память. //Прямой// доступ к файлу целесообразен в том случае, когда требуется часто менять содержимое записей и просматривать их в произвольном порядке. Так, бронированные места в зале театра, меняющиеся от спектакля к спектаклю уместно хранить в файле прямого доступа. Вы, как программист, должны предусмотреть размещение каждого символа в файле прямого доступа. В этом есть смысл: можно определить структуру файла в соответствии с Вашими потребностями.Вы сами регулируете поток данных в файле, и поэтому важно тщательно продумать его структуру. Разработка структуры файла не составит для Вас труда, если ясно представлять себе, что происходит в программе. Перейдём теперь к детальному описанию средств языка [[msx:basic:]], предназначенных для работы с файлами данных //прямого// доступа. {{anchor:n921}} ==== IX.2.1. Контрольные буферы файлов ==== {{anchor:maxfiles1}} Оператор MAXFILES=A , где: * ''MAX'', ''FILES'' — служебные слова; * А — арифметическое выражение, целая часть значения которого принадлежит отрезку [0,15], резервирует А+1 участок оперативной памяти для последующего //временного// хранения записей конкретных файлов. Например: 10 MAXFILES=5 50 MAXFILES=X+Y MAXFILES=3 Эти участки называются //буферами// или, более полно, //контрольными буферами// файлов ("Field Control Buffers" — FCB) и обозначаются: FCB 0, FCB 1,… . Каждый FCB занимает 265 байтов, из которых 9 байтов предназначены для управляющей информации, а 256 байтов — для данных. Следует иметь в виду, что FCB0 и FCB1 объявлены по умолчанию и что FCB0 используется многими операторами (''SAVE'', ''LOAD'', ''MERGE'', ''RUN'' и т.п.). При выполнении оператора ''MAXFILES='' кроме резервирования буферов производится "чистка" значений переменных и закрытие всех ранее открытых файлов данных. При выполнении операции //чтения// запись из файла помещается в контрольный буфер файла, а при выполнении операции вывода, наоборот, содержимое буфера переносится в файл, в область, отведённую для записи с указанным номером. После выполнения операции чтения данные необходимо выбирать из буфера файла, а перед выполнением операции //вывода// данные должны быть помещены в буфер файла. {{anchor:varptr}} Функция VARPTR(#n) , где: * ''VARPTR'' ("VARiable PoinTeR" — "указатель переменной") — служебное слово; * n — арифметическое выражение, целая часть значения которого определяет номер FCB (от 0 до значения выражения, стоящего в правой части оператора ''MAXFILES=''), возвращает //адрес// X байта, начиная с которого расположен в памяти FCBn. Если файл не существует, то выдаётся сообщение об ошибке: "Illegal function call". {{anchor:e0921-01}} Приведём простейший пример: \\ {{.examples:0921-01.bas|}} \\ [[+tab|wmsxbpge>0921-01.bas]] 10 MAXFILES=2:X=VARPTR(#0):Y=VARPTR(#1):Z=VARPTR(#2) 20 PRINT Y-X;Z-Y run 265 265 Ok Взгляните на схему расположения информации в FCBn : Управляющая информация ────┐ Данные ┌───┬───┬─▼─┬───┬───┬───┬───┐ │▧▧▧│▧▧▧│ … │▧▧▧│███│ … │███│ └───┴───┴───┴───┴───┴───┴───┘ Адреса ──▶ X X+1 X+8 X+9 X+264 ▲ │ Байт, адрес которого возвращает функция VARPTR(#n) //Контрольный буфер файла// (FCB) ^ Номер байта ^ Имя байта ^ Содержимое байта ^ |X |FL.MOD|Тип файла: \\ 1 — OPEN FOR INPUT \\ 2 — OPEN FOR OUTPUT \\ 2 — OPEN FOR APPEND (для диска) \\ 4 — файл прямого доступа (для диска) \\ 4 — файл последовательного доступа, открытый и для чтения, и для записи, например OPEN "COM:" AS#1 \\ 8 — OPEN FOR APPEND (для устройства MEM:)| |X+1|FL.FCA|Ссылка на область памяти, в которой хранится [[#file_specification|спецификация файла]]| |X+2|FL.LCA|:::| |X+3|FL.LSA| ? | |X+4|FL.DSK|Номер текущего устройства: \\ 0 — активное устройство по умолчанию; \\ 1 — устройство A: \\ 2 — устройство B: \\ 3 — устройство C: \\ 4 — устройство D: \\ 5 — устройство E: \\ 6 — устройство F: \\ 7 — устройство G: \\ 8 — устройство H: \\ &hFC — устройство GRP: \\ &hFD — устройство CRT: \\ &hFE — устройство LPT: \\ &hFF — устройство CAS: \\ Нестандартные устройства: \\ &hD4 — устройство COM: (локальная сеть [[msx:msx_1]]) \\ &hC0 — устройство MEM:| |X+5|FL.SLB| ? | |X+6|FL.BPS| ? | |X+7|FL.FLG| ? | |X+8|FL.OPS| ? | |X+9|FL.BUF|Содержимое записи файла (256 байт)| {{anchor:file_specification}} //Спецификация файла// ^ Номер байта ^ Содержимое байта ^ Количество байт ^ |+00|Номер дисковода (0 — по умолчанию,\\ 1 — A:)| 1 | |+01|Имя файла| 8 | |…|:::|:::| |+08|:::|:::| |+09|Расширение имени файла| 3 | |+12|Номер текущего блока| 2 | |+14|Текущий размер записи (по умолчанию равен 128)| 2 | |+16|Размер файла в байтах| 4 | |+20|Дата изменения файла| 2 | |+22|Время изменения файла| 2 | |+24|Идентификатор устройства| 1 | |+25|Расположение каталога| 1 | |+26|Первый кластер файла| 2 | |+28|Последний кластер файла| 2 | |+30|Последний доступный кластер (относительно начала файла)| 2 | |+32|Номер текущей записи файла последовательного доступа | 1 | |+33|Номер случайной записи для файла прямого доступа (байты 33,34,35 — если размер записи больше 63; байты 33,34,35,36 — если размер записи меньше 64)| 4 | |+34|:::|:::| |+35|:::|:::| |+36|:::|:::| {{anchor:n922}} ==== IX.2.2. Операторы OPEN и CLOSE ==== {{anchor:open}} Для работы с файлами данных,уже существующими на дискетах или вновь организуемыми, необходимо произвести их //открытие//. Делается это оператором OPEN B AS[#]n [LEN=m] , где: * ''OPEN'' ("открыть"), LEN("LENgth" — "длина") — служебные слова; * B — строковое выражение, значение которого определяет имя файла; * n, m — арифметические выражения, целые части значений которых определяют соответственно //номер// контрольного буфера файла и //длину// его записи в байтах; * целая часть значения n должна принадлежать отрезку [0,6], так как дисковод может одновременно работать только с //семью// различными файлами; * целая часть значения m должна принадлежать отрезку [1,256] (по умолчанию значение m равно 256). Все записи файла с //прямым// доступом имеют одинаковую длину, которая (в байтах) задаётся параметром m . Это значение определяет способ разбиения на записи дискового пространства, отведённого для файла. Например, если длина записи равна 50,то 6–я запись будет располагаться со смещением 300 (50×6) от начала файла; * # — необязательный символ, никак не влияющий на выполнение оператора ''OPEN'' . При выполнении оператора ''OPEN'' файлу с именем В назначается для работы контрольный буфер с номером n. Кроме того: * с дискеты в буфер заносится управляющая информация о файле (если файл с именем B уже существует) или * эта информация создаётся на дискете (если файл с именем В формируется заново). Вся эта процедура и называется //открытием// файла. Отметим, что один файл В не может быть открыт сразу по нескольким FCB! \\ Например: 10 OPEN "А" AS#1 MAXFILES=2:OPEN"Старт"AS#2 90 OPEN "klukva" AS#1 LEN=50 MAXFILES=5:OPEN"Финиш"AS#3 LEN=100 Оператор ''OPEN'' открывает файл с //прямым// доступом, если спецификации режимов ''FOR INPUT'', ''OUTPUT'' или ''APPEND'' опущены. {{anchor:close}} Если программа закончит запись в файл, а в буфере останутся некоторые, не записанные на дискету данные, программа должна тем или иным способом все же завершить перепись содержимого буфера. Сделать это можно с помощью оператора //закрытия// файла, к изучению которого мы и приступаем. Оператор CLOSE [[#]N1,[#]N2,… ,[#]Nk] , где: * ''CLOSE'' ("to close" — "закрывать") — служебное слово; * N1, N2, …, Nk — арифметические выражения, целые части значений которых должны принадлежать отрезку [0,15], организует //закрытие// открытых с помощью оператора ''OPEN'' файлов, имеющих номера контрольных буферов файлов, равных значениям выражений: N1, N2, …, Nk . Оператор ''CLOSE'' без параметров закрывает //все// открытые на данный момент файлы данных. Однако большинство программистов предпочитают иметь гарантированный точный результат работы оператора ''CLOSE'' и поэтому указывают в нем номера файлов в явном виде. //Закрытый// файл становится недоступным для формирования новых или обновления оператором ''PUT'' уже имеющихся записей. Приведём примеры синтаксиса оператора ''CLOSE'' : - CLOSE - CLOSE #0 - CLOSE 1.5,7 Заметим, что закрытие всех ранее открытых файлов происходит также при выполнении операторов ''END'', ''[[010#clear|CLEAR]]'', ''LOAD'', ''MAXFILES='', ''NEW'' и любом //изменении// текста программы ! Пока файл не закрыт, существует опасность, что прекращение работы программы — из–за ошибки пользователя, отключения электроэнергии или ошибки в программе — приведёт к утрате данных или даже к повреждению дискеты. Опыт подсказывает, что желательно закрывать файл, как только исчезнет необходимость в том, чтобы он был открыт. {{anchor:n923}} ==== IX.2.3. Оператор FIELD ==== Как мы уже отмечали,под каждый контрольный буфер файла (FCB) отводится 265 байтов, 256 из которых непосредственно предназначены для временного хранения //записи// файла. Перед началом непосредственной работы с контрольным буфером файла необходимо произвести его разбиение на отдельные //поля// для формирования в них конкретных значений. Делается это при помощи оператора {{anchor:field}} FIELD [#]n, M1 AS γ1, M2 AS γ2,… , Mk AS γk , где: * ''FIELD'' ("field" — "поле") — служебное слово; * n — арифметическое выражение, целая часть значения которого определяет номер контрольного буфера файла; * M1,M2, …,Mk — целые числа. \\ Учтите, что суммарная длина всех объявляемых в операторе ''FIELD'' полей не должна превосходить длины записи, установленной оператором ''OPEN''. Нарушение этого правила приводит к ошибке; * γ1,γ2, …,γk — строковые переменные (простые или с индексами), называемые //буферными// переменными; * # — необязательный символ, никак не влияющий на выполнение оператора. При выполнении команды ''FIELD'' производится задание формата записи. Это выражается в выделении каждому значению буферной переменной γs //поля// из Ms байтов (s=1, 2, …k). Ни одну из буферных переменных оператора ''FIELD'' нельзя использовать ни в каких модификациях оператора ''INPUT'' и ни одной из них нельзя присваивать значение оператором ''LET''. Нарушение любого из этих правил приводит к утрате соответствия, установленного оператором ''FIELD'', вследствие чего программа не может больше использовать такую переменную для занесения нужных значений в записи файла или для их извлечения. Разбиение FCB на поля оператором ''FIELD'' покажем на рисунке: Управляющая информация─┐ M1 M2 … Mk (9 байтов) ┌────▼───┬─────────┬─────┬───┬───────────┐ │████████│ │ │ … │ │ └────────┴────▲────┴──▲──┴───┴─────▲─────┘ │ │ │ Значения ───▶ γ1 γ2 … γk Например, оператор ''FIELD #1,200 AS X$, 12 AS Y$'' отводит 200 байт для переменной X$ и 12 байтов — для переменной Y$. Заметим, что этот оператор будет выполнен только в том случае, если файл был предварительно открыт. {{anchor:e0923-01}} __//Пример 1//__. В качестве примера рассмотрим файл с прямым доступом, содержащий информацию о личной библиотеке. Каждая запись содержит следующую информацию: - номер книги (2 байта); - фамилию автора книги (15 байтов); - название книги (30 байтов); - признак наличия книги (1 байт); - информацию о читателе, взявшем книгу (22 байта); - дату выдачи книги (10 байтов). Для открытия этого файла и описания структуры записи можно использовать следующие операторы: \\ {{.examples:0923-01.bas|}} \\ [[+tab|wmsxbpge>0923-01.bas]] 10 OPEN "Библтека" AS#1 LEN=80 'В имени - не более 8 символов! 20 FIELD #1,2 AS NUMBER$,15 AS AUTHOR$,30 AS BOOK$,1 AS CODE$, 22 AS RADER$,10 AS DATE$ Отметим, что разрешается использовать несколько команд ''FIELD'' с разными форматами для одного и того же буфера n. Всегда действует то разбиение FCBn на поля, которое предложено последней выполненной командой ''FIELD''. {{anchor:e0923-02}} __//Пример 2//__. \\ {{.examples:0923-02.bas|}} \\ [[+tab|wmsxbpge>0923-02.bas]] 10 MAXFILES=3:OPEN"Student" AS#2 LEN=40 20 FIELD #2,28 AS M1$,12 AS M2$ 30 FIELD #2,10 AS M1$,5 AS M2$,24 AS K$ Оператор ''FIELD'' должен выполняться перед обращениями к файлу с помощью операторов ''PUT'' и ''GET'' (см. [[#n926|раздел IX.2.6.]]). Прежде чем обратиться к файлу, Вы должны продумать, какие данные будут составлять записи, каковы их тип и длина (размер). В результате Вы получите документ, часто называемый //логической структурой файла//. С ним вам предстоит работать в течение всего времени "жизни" файла. Поскольку в этом документе указано число байтов, отведённое под каждую запись, можно заранее установить количество байтов, которое потребуется на дискете для конкретного файла, а так как известен и тип применяемых данных, то становится очевидным, какие придётся вводить переменные. Важно отметить, что при известной логической структуре файла его в дальнейшем могут использовать другие программы. Ниже приведена структура записи в файле и дан расчёт размера файла для 24 записей о пловцах. Каждая запись содержит поля для имени пловца, клуба, к которому он принадлежит, дисциплины, в которой он выступает, а также поля для его возраста и лучшего показанного результата. //Имя файла//: SWIMMER . \\ //Тип файла//: прямого доступа. \\ //Содержимое//: 24 записи о пловцах. ^ Имя \\ переменной ^ Описание поля ^ Длина поля \\ (байт) ^ Тип данных ^ | N$ |Имя пловца| 30 |30 символов│ | T$ |Принадлежность к клубу| 20 |20 символов| | E$ |Дисциплина| 8 |8 символов| | A$ |Возраст| 2 |Целое число| | T |Лучший результат| 4 |Вещественное число| | **Итого**:|| **64** | | Длина и тип каждого поля указаны вместе с переменными, которые в Вашей программе будут хранить данные, извлечённые из записей. Совершенно необязательно использовать одни и те же переменные во всех программах, обращающихся к этому файлу, однако такое единообразие позволит легче проследить ход обработки данных в любой программе. Ещё раз подчеркнём, что длина записи в файле с прямым доступом //постоянна//. Она определяется при его создании, и каждому полю выделяется внутри записи строго определённое место. Возможные значения полей должны умещаться в этом заранее отведённом объёме памяти. Если это не продумано заблаговременно, то при выполнении программы чрезмерно "длинные" значения подвергаются усечению, а "короткие" дополняются пустующими ячейками памяти. В целях минимизации нежелательного усечения размер каждого поля обычно выбирается достаточно большим, чтобы вместить самую большую возможную величину. {{anchor:n924}} {{anchor:lset}} {{anchor:rset}} ==== IX.2.4. Операторы LSET и RSET ==== Напомним Вам, что команда ''FIELD'' определяет формат записи файла и набор буферных переменных. Далее буферные переменные не могут использоваться в операторах ''LET'', ''INPUT'', ''LINE INPUT''. При формировании в памяти конкретной записи значения буферным переменным из ''FIELD'' присваиваются операторами: LSET γ=β RSET γ=β , где: * ''LSET'' ("Left SET" — "поместить слева"), * ''RSET'' ("Right SET" — "поместить справа") — служебные слова; * γ — имя буферной переменной; * β — строковое выражение (β≠γ). Пусть буферной переменной γ отведено в буфере поле размером m байтов. Выполнение оператора ''LSET'' начинается с вычисления значения выражения β. Далее, если это необходимо, его длина приводится к величине m за счёт отбрасывания лишних //правых// символов или добавления справа недостающего количества пробелов. Полученное значение присваивается буферной переменной γ и размещается в соответствующем поле буфера файла. Оператор ''RSET'' выполняется почти так же, как и оператор ''LSET''. Разница состоит в том, что при выравнивании значения β до длины m возможные недостающие пробелы добавляются к нему не справа, а //слева//. Неиспользованные байты заполняются пробелами. Таким образом, операторы ''LSET'' и ''RSET'' гарантируют, что длина значения переменной будет приведена в соответствие с длиной, указанной в операторе ''FIELD''. {{anchor:e0924-01}} __//Пример 1//__. \\ {{.examples:0924-01.bas|}} \\ [[+tab|wmsxbpge>0924-01.bas]] 10 OPEN "EF" AS#1 LEN=9 20 FIELD #1,5 AS M$,14 AS L$ 30 INPUT R$:LSET M$=R$ 40 INPUT R$:RSET L$=R$ 50 PRINT M$:PRINT L$ run ? КРАТЕР M$ ? НЕБОСВОД ┌───┬───┬───┬───┬───┬ КРАТЕ │ K │ Р │ А │ Т │ Е │ НЕБОСВОД └───┴───┴───┴───┴───┴ Ok 5 байтов {{anchor:e0924-02}} __//Пример 2//__. \\ {{.examples:0924-02.bas|}} \\ [[+tab|wmsxbpge>0924-02.bas]] Приведём фрагмент программы, в котором формируется запись файла, содержащего информацию о личной библиотеке. В буфер заносится информация о романе Л.Н.Толстого "Война и мир". Структура записи была рассмотрена ранее. 10 OPEN "Библтека" AS#1 LEN=80 20 FIELD #1,2 AS NUMBER$,15 AS AUTHOR$,30 AS BOOK$,1 AS CODE$, 22 AS RADER$,10 AS DATE$ 30 LSET NUMBER$=10 'Шифр книги 40 LSET AUTHOR$="Л.Н.Толстой" 50 LSET BOOK$="Война и мир" 60 LSET CODE$="X" 'X - книга хранится 70 LSET READER$=" " 'Читатель, разумеется, отсутствует 80 LSET DATE$="10.5.1988" Команды ''LSET'' и ''RSET'' можно использовать не только при работе с файлами. {{anchor:e0924-03}} __//Пример 3//__. \\ {{.examples:0924-03.bas|}} \\ [[+tab|wmsxbpge>0924-03.bas]] 10 L$=SPACE$(20):Z$="Волк" 20 RSET L$=Z$:PRINT L$ {{anchor:n925}} ==== IX.2.5. Функции MKI$(), MKS$(),MKD$(), CVI(), CVS(), CVD() ==== Вам, конечно, известно, что буферные переменные являются строковыми. Пусть γ — буферная переменная и ей командой ''FIELD'' в FCB отведено поле длиной m байтов. Если требуется "упаковать" в γ числовое значение, то пользуются функциями: - {{anchor:mki}} MKI$(L) , где: * ''MKI'' ("MaKe Integer" — "преобразовать целое значение") — служебное слово; * L — арифметическое выражение целого типа; * m=2; - {{anchor:mks}} MKS$(L) , где: * ''MKS'' ("MaKe Single" — "преобразовать значение одинарной точности") — служебное слово; * L — арифметическое выражение одинарной точности; * m=4; - {{anchor:mkd}} MKD$(L) , где: * ''MKD'' ("MaKe Double" — "преобразовать значение двойной точности") — служебное слово; * L — арифметическое выражение двойной точности; * m=8. Каждая из этих функций преобразует значение арифметического выражения L к строковому типу. После этого операторами ''[[#lset|LSET]]'' или ''[[#rset|RSET]]'' эти значения можно разместить в γ и соответствующем поле буфера. Обращаем Ваше внимание на тот факт, что функции ''MKI$()'', ''MKS$()'' и ''MKD$()'' не переводят числовые величины в эквивалентные им знаки кода ASCII, как это делается при использовании других функций. Они просто "упаковывают" соответствующие значения в два,четыре или восемь знаков по той же схеме, которая реализуется в компьютере для представления числовых величин в оперативной памяти. Именно поэтому с помощью оператора ''PRINT'' невозможно выдать на печать или экран дисплея результаты работы функций ''MKI$()'', ''MKS$()'' и ''MKD$()'' ! __//Пример 1//__. - функция ''MKI$(17217)'' возвращает строку "AC". Рассмотрим, как это получается: 17217=&B0100001101000001=&H4341=&H43×256+&H41=67×256+65 └──────┘└──────┘ ▲ ▲ C A │ └─ Код символа "A" └──────── Код символа "C" - ''MKS$(4.14141)'' возвращает строку %% "AAAA" %% {{anchor:e0925-02}} __//Пример 2//__. \\ {{.examples:0925-02.bas|}} \\ [[+tab|wmsxbpge>0925-02.bas]] 1 A$=MKI$(&HE276):PRINT HEX$(ASC(MID$(A$,1,1)));" ";HEX$(ASC(MID$(A$,2,1))) 76 E2 Ok {{anchor:e0925-03}} __//Пример 3//__. \\ {{.examples:0925-03.bas|}} \\ [[+tab|wmsxbpge>0925-03.bas]] 10 MAXFILES=5:OPEN "LU" AS#4 20 FIELD #4, 2 AS A$, 4 AS B$, 8 AS E$ 30 INPUT X%:LSET A$=MKI$(X%) 40 INPUT Y!:LSET B$=MKS$(Y!) 50 INPUT Z#:LSET E$=MKD$(Z#) 60 PRINT A$;" ";B$;" ";E$ 70 RSET A$=MKI$(X%):RSET B$=MKS$(Y!):RSET E$=MKD$(Z#) 80 PRINT A$;" ";B$;" ";E$ run ? 1096 ? 1.535 ? -3.4 H A5 a4 H A5 a4 Ok Функции ''MKI$()'', ''MKS()'' и ''MKD()'' выполняют обратное преобразование по отношению к функциям ''CVI()'', ''CVS()'' и ''CVD()'', к рассмотрению которых мы сейчас приступаем. Пусть в буфер с дискеты считана запись, и в некотором её поле,определённом по команде ''FIELD'' элементом m AS γ "упаковано" числовое значение. "Распаковка" его, или выборка из γ этого значения, реализуется одной из следующих функций: - {{anchor:cvi}} CVI(γ) , где: * ''CVI'' ("ConVert to Integer" — "преобразовать к целому") — служебное слово; * γ — имя буферной переменной; * m=2; - {{anchor:cvs}} CVS(γ) , где: * ''CVS'' ("ConVert to Single" — "преобразовать к значению одинарной точности") — служебное слово; * γ — имя буферной переменной; * m=4; - {{anchor:cvd}} CVD(γ) , где: * ''CVD'' ("ConVert to Double" — "преобразовать к значению двойной точности") — служебное слово; * γ — имя буферной переменной; * m=8. Эти функции преобразуют строки символов в числа. Аргумент состоит из 2, 4 или 8 байтов и преобразуется в целое число, либо число с одинарной или двойной точностью в зависимости от вида используемой функции (''CVI'', ''CVS'' или ''CVD''). //Пример 4//. - print CVI("AC") 17217 Ok , так как print MKI$(17217) AC Ok - print CVS("GWYF") 5759460 Ok , так как print MKS$(5759460) GWYF Ok Посмотрите на схему… "G" "W" "Y" "F" 0100 0111 0101 0111 0101 1001 0100 0110 ▲───▲──── 5 7 5 9 4 6 │ │ │ Порядок числа = &B1000111-&B1000000 = &B111 = 7 Знак числа Сравните эти результаты с представлением чисел в памяти компьютера (см. далее [[010|главу X]]). {{anchor:e0925-05}} __//Пример 5//__. \\ {{.examples:0925-05.bas|}} \\ [[+tab|wmsxbpge>0925-05.bas]] 10 OPEN "SL" AS#1 LEN=8:FIELD #1,8 AS R$ 20 INPUT X:RSET R$=MKD$(X) 40 PRINT R$,CVD(R$) run ? 123 C0 123 Ok {{anchor:n926}} ==== IX.2.6. Операторы PUT и GET ==== FIXME {{anchor:put}} Для пересылки ("сброса") сформированной в оперативной памяти записи на дискету используется оператор PUT [#]n[,P] , где: * ''PUT'' ("записать", "разместить") — служебное слово; * n, P — арифметические выражения, целые части значений которых задают соответственно номер контрольного буфера файла и номер записи. До выполнения оператора ''PUT'' в оперативной памяти: * оператором ''MAXFILES='' должен быть объявлен контрольный буфер файла FCBn ; * открыт некоторый файл В, связанный с FCBn (оператором ''OPEN''); * задан формат его записей (оператором ''FIELD'') и, наконец, * в FCBn создана сама запись (операторами ''LSET'', ''RSET''). После всей этой процедуры оператором ''PUT'' содержимое FCBn будет выведено под номером P на дискету, или, как говорят, //сформирована// новая или //обновлена// старая запись Р файла В. При открытии файла значение Р равно 0. //Текущим// значением Р считается номер той записи, с которой работал последний выполненный оператор ''PUT'' или ''GET''. Далее если в операторе ''PUT'' параметр Р не указан, то берётся его текущее значение, увеличенное на 1. Например, в операторе ''PUT #1,3'' второе число (3) определяет номер записи в файле. Если этот номер будет пропущен, то будет использовано число на единицу большее,чем в последнем выполненном операторе ''PUT'' или ''GET''. Номер записи может находиться в диапазоне от 1 до 4294967295, в чем Вы можете убедиться самостоятельно. {{anchor:e0926-01}} __//Пример 1//__. \\ {{.examples:0926-01.bas|}} \\ [[+tab|wmsxbpge>0926-01.bas]] 10 REM формирование файла 20 MAXFILES=2:OPEN"массив" AS#2 LEN=8:FIELD #2,8 AS M 50 FOR I=1 TO 30 60 INPUT"Введите число";А:LSET M=MKD$(A):PUT #2 90 NEXT 100 CLOSE #2 {{anchor:e0926-02}} __//Пример 2//__. \\ {{.examples:0926-02.bas|}} \\ [[+tab|wmsxbpge>0926-02.bas]] 10 'Объявление FCB0, FCB1, FCB2 и FCB3 20 'Открытие файла "рыба" с буфером #2 30 MAXFILES=3:OPEN "Рыба" AS#2 LEN=13 40 'Определение формата записи 50 FIELD #2,8 AS L$, 5 AS M$ 60 'Формирование первых 10 записей 70 FOR K=1 TO 10 80 INPUT"X$-8";X$:INPUT"Y$-5";Y$ 90 LSET L$=X$:RSET M$=Y$:PUT #2,K 99 NEXT:END Пусть открыт некоторый файл данных, связанный с буфером FCBn. Полезную информацию о файле можно извлечь с помощью функций ''[[#LOF]]'' и ''[[#LOC]]''. {{anchor:get}} Для считывания записей файла с дискеты в оперативную память используется оператор GET [#]n[,P] , где: * ''GET'' ("to get" — "получать") — служебное слово; * n, P — арифметические выражения, целые части значений которых задают соответственно номер контрольного буфера файла и номер записи. До выполнения оператора ''GET'' необходимо: * объявить контрольный буфер файла FCBn (оператором ''MAXFILES=''); * открыть некоторый файл данных В,связанный с FCBn (оператором ''OPEN''); * задать формат его записей (оператором ''FIELD''). После всей этой процедуры по оператору ''GET'' с диска в буфер # n будет считана запись с номером Р. Фактически будут сформированы значения всех строковых переменных буфера (числовые значения буферных переменных надо "распаковать" с помощью функций ''CVI'', ''CVS'' и ''CVD''). Например, оператор ''GET #1,3'' выполняет передачу записи с номером 3 из файла #1 в буфер полей. Если в записи оператора параметр Р отсутствует, то берётся текущее значение этого параметра, увеличенное на единицу (как и в операторе ''PUT''). {{anchor:e0926-03}} __//Пример 3//__. \\ {{.examples:0926-03.bas|}} \\ [[+tab|wmsxbpge>0926-03.bas]] 10 REM Считывание из файла "Массив" 20 MAXFILES=2:OPEN"Массив" AS#2 LEN=8:FIELD 2,8 AS M 50 FOR I=30 TO 1 STEP-1 60 GET 2,I:PRINT CVD(M); 80 NEXT {{anchor:e0926-04}} __//Пример 4//__. \\ {{.examples:0926-04.bas|}} \\ [[+tab|wmsxbpge>0926-04.bas]] 1 OPEN"числа" AS#1 LEN=10 2 FIELD #1,2 AS A$(1),2 AS A$(2),2 AS A$(3),2 AS A$(4),2 AS A$(5) 3 FOR I=1 TO 5:LSET A$(I)=MKI$(I):NEXT I 8 PUT #1,1:CLOSE #1:END 10 OPEN"числа" AS#1 11 FIELD #1,2 AS B$(1),2 AS B$(2),2 AS B$(3),2 AS B$(4),2 AS B$(5) 12 GET #1,1 13 FOR I=1 TO 5:A(I)=CVI(B$(I)):NEXT I 18 P=1:FOR T=1 TO 5:P=P+A(T):NEXT T 19 PRINT P:CLOSE #1:END {{anchor:e0926-05}} __//Пример 5//__. \\ {{.examples:0926-05.bas|}} \\ [[+tab|wmsxbpge>0926-05.bas]] 10 CLOSE:OPEN"числа" AS#1 LEN=25 30 FIELD #1,5 AS A$(1),5 AS A$(2),5 AS A$(3),5 AS A$(4), 5 AS A$(5) 40 FOR T=1 TO 5 50 LINEINPUT"Еще слово:";J$(T):LSET A$(T)=J$(T) 60 NEXT T 70 PUT#1,1:CLEAR 'Чистка оперативной памяти 90 OPEN"числа" AS#1 100 FIELD #1,5 AS B$(1),5 AS B$(2),5 AS B$(3),5 AS B$(4), 5 AS B$(5) 110 GET#1,1:U$="" 120 FOR T=1 TO 5:U$=U$+B$(T):NEXT T 150 PRINT"Сумма:";U$ {{anchor:e0926-06}} __//Пример 6//__. \\ {{.examples:0926-06.bas|}} \\ [[+tab|wmsxbpge>0926-06.bas]] 10 CLOSE:OPEN"числа" AS#1 LEN=25 20 FIELD #1,5 AS A$(1),4 AS A$(2),5 AS A$(3),4 AS A$(4), 5 AS A$(5) 30 FOR T=1 TO 5 STEP 2 40 LINEINPUT"Еще слово:";J$(T) 50 LSET A$(T)=J$(T):NEXT 60 FOR T=2 TO 4 STEP 2 70 INPUT"Еще число";J(T) 80 LSET A$(T)=MKS$(J(T)):NEXT 90 PUT #1,1:CLEAR 'Чистка оперативной памяти 110 OPEN"числа" AS#1 120 FIELD #1,5 AS B$(1),4 AS B$(2),5 AS B$(3),4 AS B$(4), 5 AS B$(5) 130 GET #1,1:U$=B$(1) 140 FOR T=2 TO 4 STEP 2 150 U$=U$+STR$(CVS(B$(T)))+B$(T+1):NEXT 160 PRINT"Сумма:";U$ Отметим ключевой момент при работе с файлами //прямого// доступа: отслеживание "невидимых" указателей. Их два: для дискеты и для буфера. Первый указатель содержит ссылку на текущую запись и задаётся номером в операторах ''PUT'' или ''GET''. Буферный указатель ссылается на элемент данных — переменную, которая в этот момент пишется или читается. Он задаётся длиной полей в операторе ''FIELD''. Ниже приведены //две схемы//, дающие наглядное представление о последовательности операций, которые должны быть выполнены при перемещениях //записей// файлов прямого доступа из оперативной памяти на дискету и в обратном направлении. - Общая схема формирования //новых// записей уже существующего или вновь создаваемого файла F. * А. В оперативной памяти резервируется буфер (оператором ''MAXFILES='') * B. //Открывается// файл F (оператором ''OPEN'') * C. Производится распределение полей буфера файла под значения переменных (оператором ''FIELD'') * D. В буфере формируется запись (при помощи операторов ''SET'', ''RSET'' и функций ''MKI$()'', ''MKS$()'', ''MKD$()'' * E. Производится "сброс" записи из буфера на дискету с присваиванием ей некоторого номера (оператором ''PUT'') * F. Файл F //закрывается// (оператором ''CLOSE'') {{anchor:e0926-07}} \\ __//Пример 7//__. Запись слова в файл прямого доступа. \\ {{.examples:0926-07.bas|}} \\ [[+tab|wmsxbpge>0926-07.bas]] 10 MAXFILES=2:OPEN "EASY" AS#2:FIELD #2,18 AS N$,110 AS D$ 20 LSET N$="Психокомпьютерапия":LSET D$=" ":PUT #2,1:CLOSE #2 - Общая схема //считывания// записей из уже существующего файла. * А. В оперативной памяти резервируется буфер (оператором ''MAXFILES='')│ * B. //Открывается// файл F (оператором ''OPEN'') * C. Производится распределение полей буфера файла под значения переменных (оператором ''FIELD'') * D. Производится считывание с диска в буфер оперативной памяти записи с конкретным номером (оператором ''GET'') * E. По записи из буфера в соответствии с распределением его поля формируются значения требуемых переменных (при помощи функций ''CVI()'', ''CVS()'', ''CVD()''). После перенесения записи в буфер Вы можете манипулировать данными, полученными из файла, так же, как любыми другими переменными. Пункты D и E повторяются столько раз, сколько это требуется * F. Файл F //закрывается// (оператором ''CLOSE'') {{anchor:e0926-08}} __//Пример 8//__. Чтение слова из файла прямого доступа. \\ {{.examples:0926-08.bas|}} \\ [[+tab|wmsxbpge>0926-08.bas]] 10 MAXFILES=2:OPEN "EASY" AS#2:FIELD #2,18 AS N$,110 AS D$ 20 GET #2,1:PRINT N$:CLOSE #2 run Психокомпьютерапия Ok В заключении этого пункта приведём примеры, иллюстрирующие действие изученных Вами операторов и функций при работе с дисковыми файлами данных прямого доступа. {{anchor:e0926-09}} __//Пример 9//__. \\ {{.examples:0926-09.bas|}} \\ [[+tab|wmsxbpge>0926-09.bas]] 5 CLS 10 OPEN "ЭКЗАМЕН" AS#1 LEN=45:FIELD#1,5 AS G$,25 AS F$,1 AS O$ 25 INPUT "Введите количество студентов";N 30 FOR I=1 TO N 40 INPUT "Группа";GG$:INPUT "Ф.И.О";FF$:INPUT"Оценка";OO$ 50 LSET G$=GG$:LSET F$=FF$:LSET O$=OO$:PUT #1,I 65 NEXT:CLS 66 FOR I=1 TO N 70 GET #1,I:IF O$="5" OR O$="4" THEN PRINT G$,F$;O$ 80 NEXT:CLOSE #1 {{anchor:e0926-10}} __//Пример 10//__. Дана таблица: ^ Ф.И. ученика ^ Тема ^ Балл ^ | Фомина Н. | Графика | 5 | |:::| Массивы | 5 | | Бобкова Н. | Графика | 4 | |:::| Массивы | 3 | || … || | Герасимова Е. | Графика | 5 | |:::| Массивы | 3 | Заполнить два файла: - список учеников, у которых средний балл по двум темам ≥ 4 ; - список учеников, у которых хотя бы по одной теме балл 4 или 5. {{.examples:0926-10.bas|}} \\ [[+tab|wmsxbpge>0926-10.bas]] 10 MAXFILES=3 20 OPEN "экзамен"AS#1 LEN=39 30 FIELD #1, 15 AS I$, 10 AS T1$, 2 AS O1$, 10 AS T2$, 2 AS O2$ 31' ▲ ▲ ▲ ▲ ▲ 32' │ │ │ │ │ 33' Фамилия,имя Первая Балл по Вторая Балл по 34' тема первой теме тема второй теме 40 OPEN "Фамилия"AS#2 LEN=15 50 FIELD #2,15 AS F$ 'Фамилия ученика, у которого средний балл по 'двум темам ≥ 4 60 OPEN "особенное"AS#3 LEN=15 70 FIELD #3,15 AS F1$ 'Фамилия ученика, у которого хотя бы по одной 'теме балл 4 или 5 75 INPUT "Введите количество учащихся";N 80 FOR I=1 TO N 90 INPUT "Ф.И.";D$:LSET I$=D$:INPUT "Тема1";D$:LSET T1$=D$:INPUT"Балл";D%: LSET O1$=MKI$(D%):INPUT "Тема2";D$:LSET T2$=D$: INPUT "Балл";D%:LSET O2$=MKI$(D%):PUT#1,I 110 NEXT:A=0 'A - количество учеников, у которых средний балл по 'двум темам ≥ 4 120 FOR K=1 TO N:GET#1,K 'Заполнение файла #2 125 L=(CVI(O1$)+CVI(O2$))/2 130 IF L>=4 THEN LSET F$=I$:A=A+1:PUT #2,A 140 NEXT K 146 PRINT"Ф.И. хорошистов и отличников:" 150 FOR I=1 TO A:GET #2,I:PRINT F$:NEXT I 'Вывод на экран 170 B=0 'B - количество учеников,у которых хотя бы по одной 'теме балл 4 или 5 175 FOR K=1 TO N 'Заполнение файла #3 177 GET #1,K 180 IF CVI(O1$)=4 OR CVI(O1$)=5 OR CVI(O2$)=4 OR CVI(O2$)=5 THEN LSET F1$=I$:B=B+1:PUT #3,B 190 NEXT K 195 PRINT"Ф.И. успевающих" 200 FOR I=1 TO B:GET#3,I:PRINT F1$:NEXT I:END 'Вывод на экран {{anchor:e0926-11}} __//Пример 11//__. \\ {{.examples:0926-11.bas|}} \\ [[+tab|wmsxbpge>0926-11.bas]] 10 MAXFILES=3:OPEN"A3" AS#2 LEN=2:FIELD #2,2 AS K$ 20 POKE VARPTR(#2)+9,66:POKE VARPTR(#2)+10,65 'Вместо LSET K$="ba" 30 PUT #2,2:CLOSE#2 40 OPEN"a3"AS#2 LEN=2:FIELD #2,2 AS K$:GET #2,2:CLOSE #2 run ba Ok {{anchor:n93}} ===== IX.3. Файлы данных последовательного доступа ===== При использовании дискеты достаточно указать имя файла, чтобы компьютер начал поиск с использованием каталога. Все участки дискеты в равной степени доступны для записи и чтения, т.е. для обращения к любому участку требуется примерно одинаковое время. Напомним Вам, что файл, в котором информация может быть найдена без полного просмотра носителя, мы назвали файлом с //прямым// доступом. Файл будем называть файлом с //последовательным доступом//, если компьютер должен "просматривать" его с самого начала до момента нахождения нужной части. Поиск файла на кассетной ленте называется //последовательным//, потому что компьютер ищет требуемый файл, последовательно перематывая магнитную ленту. Любой файл можно организовать так, чтобы можно было использовать либо последовательный, либо прямой доступ, но не оба способа одновременно. Каждый способ имеет свои "за" и "против". Последовательный способ намного проще для программирования и при его реализации требуется меньше дисковой памяти, но может понадобиться больше времени для поиска информации, находящейся "в конце" длинного файла. Кроме того, обновление существующих записей в файлах с последовательным доступом трудноосуществимо, а иногда и просто невозможно. Файлы с прямым доступом требуют более сложного программирования и занимают обычно больше места на дискете, но очень легко поддаются обновлению, и поиск нужной информации осуществляется с одинаковой скоростью. Если при каждом обращении к файлу Вы собираетесь использовать почти все данные, а менять их содержимое часто не предполагается, то выбирайте метод //последовательного// доступа. Его применение будет и более оптимальным и облегчит вам программирование. Файлы данных последовательного доступа состоят из отдельных групп значений, называемых //логическими// строками (или просто //строками//). Логические строки не имеют номеров и их можно считывать с дискеты или магнитной ленты в оперативную память или записывать из памяти на дискету или магнитную ленту лишь последовательно друг за другом, причём запись производится от начала или конца файла, а чтение — только от его начала. Каждая логическая строка имеет специальную //концевую// метку, а весь файл имеет ещё и метку EOF ("End Of File" — "конец файла"). Кроме того, любой конкретный файл открывается или только для чтения, или только для записи, но не для одновременного выполнения этих операций. Для работы с файлами данных //последовательного// доступа в [[msx:disk_basic]] предусмотрен ряд операторов и функций. {{anchor:n931}} ==== IX.3.1. Оператор MAXFILES=, OPEN и CLOSE ==== {{anchor:maxfiles}} Перемещение логических строк последовательных файлов из оперативной памяти на дискету и в обратном направлении производится через //контрольные буферы файлов//. Последние объявляются оператором ''[[009#maxfiles|MAXFILES=]]''. Максимальное количество файлов, которые могут быть открыты одновременно, устанавливается оператором MAXFILES=A , где: * ''MAX'', ''FILES'' — служебные слова; * A — арифметическое выражение, целая часть значения которого принадлежит отрезку [0,15]. При включении компьютера значение параметра A равно 1. Таким образом, если Вы хотите открыть //только один// файл, то использование оператора ''MAXFILES'' необязательно. Файл #0 всегда открыт. [[msx:disk_basic]] использует контрольный буфер этого файла для "своих нужд" (он используется при выполнении операторов ''LOAD'', ''SAVE'', ''KILL'', ''RUN'', ''MERGE''). При работе с последовательными файлами буфера используются самым простым способом: пересылаемые в файл данные накапливаются в буфере файла, а по заполнении буфера его содержимое сразу целиком переписывается в дисковый файл;при этом буфер файла очищается для следующей порции выходных данных. При чтении файла соответствующие данные поступают из того же самого буфера, а не считываются непосредственно с поверхности дискеты. Как только все необходимые данные считаны из буфера, средства [[msx:basic:]] обеспечивают повторное его заполнение информацией из дискового файла. Учтите,что при использовании оператора ''MAXFILES='' автоматически выполняется оператор ''[[010#clear|CLEAR]]'', но если Вы используете в программе оба оператора, то располагайте оператор ''MAXFILES='' вслед за оператором ''[[010#clear|CLEAR]]''. {{anchor:open_for}} Вам, конечно же, ясно, что перед использованием файла Вы должны объявить его //открытым//. Открытие файла осуществляется оператором ''OPEN'', в котором задаётся: * имя устройства (''A:'', ''B:'', ''MEM:'', ''CAS:'', ''CRT:'', ''GRP:'', ''LPT:'', ''COM:''); * имя файла; * направление потока данных; * номер, присвоенный файлу для передачи данных. Синтаксис оператора ''OPEN'': ⎧ INPUT OPEN B FOR ⎨ OUTPUT AS[#]n ⎩ APPEND , где: * ''OPEN''("открыть"), FOR("для"), ''INPUT''("ввод"), ''OUTPUT''("вывод"), ''APPEND''("присоединение") — служебные слова; * В — строковое выражение, значение которого задаёт имя устройства и имя файла. Сейчас мы познакомим Вас с именами //устройств//: * устройство ''CRT:'' отвечает за вывод информации на //текстовый// экран ("CaRet" — "символ"); * устройство ''GRP:'' отвечает за вывод информации на экран в //графических// режимах ("GRaPhics" — "графика"); * устройство ''LPT:'' отвечает за вывод информации на //принтер// ("Line PrinT" — "печать строки"); * устройство ''COM:'' (только для компьютеров [[msx:msx_1]]) отвечает за движение информации по //локальной// сети ("COMmunication" — "передача данных"); * устройство ''MEM:'' (только для [[msx:msx_2]]) — это не что иное, как RAM диск ("MEMory" — "память"); * устройство ''CAS:'' является накопителем на магнитной ленте (//магнитофоном//) ("CASsette type" — "кассетная лента"); * n — арифметическое выражение, целая часть значения которого принадлежит: * отрезку [0,6] для файлов на дискете, * отрезку [0,15] для файлов на других устройствах, и определяет номер контрольного буфера файла; * # — необязательный символ. При выполнении оператора ''OPEN'' файлу В "назначается" для работы контрольный буфер файла с номером n. Параметры ''INPUT'', OUTPUT и APPEND указывают направление последующего движения информации относительно компьютера. Оператор ''OPEN'' с параметром ''INPUT'' открывает файл //для ввода// строк с дискеты в буфер. Чтение будет организовано от начала файла. Оператор ''OPEN'' с параметром ''OUTPUT'' открывает файл //для вывода// строк с буфера на дискету. Запись будет осуществляться от начала файла. Оператор ''OPEN'' с параметром ''APPEND'' открывает файл для вывода строк с буфера на дискету,но запись будет производиться с //конца// файла. Будьте осторожны: параметр ''APPEND'' не может использоваться при открытии файлов на устройствах ''CAS:'', ''CRT:'', ''GRP:'', ''LPT:'' и ''COM:'' ! Параметр ''INPUT'' не может использоваться при открытии файлов на устройствах ''CRT:'', ''GRP:'' и ''LPT:'' ┌───────────────────────────┐ ┌───────────────────────┐ │ Контрольный ◀───INPUT──│ │ │ буфер │──OUTPUT──▶ Дискета │ │ файла │──APPEND──▶ │ └───────────────────────────┘ └───────────────────────┘ Оператор ''OPEN'' с параметром ''FOR OUTPUT'' создаёт новый дисковый файл с заданным именем. Если файл с таким именем уже есть,то он автоматически уничтожается и создаётся новый файл с тем же именем. Оператор ''OPEN…FOR APPEND'' обеспечивает поиск названного файла среди уже существующих, с тем чтобы добавить новые записи в его конец, но если требуемого файла найти не удалось, то автоматически создаётся новый файл с заданным именем. Модификация оператора с параметром ''FOR INPUT'' реализует поиск данных с конкретным именем, отсутствие которого означает ошибку. __//Примеры//__: - OPEN"CAS:ADDRESS" FOR INPUT AS #1 |Устройство|CAS:| |Файл|ADDRESS| |Направление|INPUT (файл, сохранённый на ленте, нужно ввести)| |Номер файла|1| - OPEN"ADDRESS" FOR OUTPUT AS #1 |Устройство: A: |(по умолчанию в [[msx:disk_basic]])| |Файл|ADDRESS| |Направление|OUTPUT (файл должен быть создан на дискете)| |Номер файла|1| - OPEN"B:ADDRESS" FOR APPEND AS #2 |Устройство|B:| |Файл|ADDRESS| |Направление|APPEND (добавление к уже существующему файлу)| |Номер файла|2| Можно открыть файл с последовательным доступом в режиме записи, используя один номер файла, и в режиме чтения, используя другой. Однако каждому номеру файла будет при этом соответствовать //свой буфер//, никак не связанный с другими. Если же Вы используете только один буфер, то для изменения режима доступа к файлу последний необходимо закрыть, а затем вновь открыть. Этот приём особенно удобен, когда Вы хотите использовать в программе в любой момент только один открытый файл (''MAXFILES=1''). Однажды открытый, но не закрытый файл не может быть открыт повторно. В противном случае компьютер сообщает: "File already open". //Закрытие// файла позволяет вам использовать буфер с тем же номером для открытия другого файла. Оператор, закрывающий файлы, выглядит так: CLOSE [[#]N1,[#]N2,… ,[#]Nk] , где: * ''CLOSE'' — служебное слово; * N1, N2, …, Nk — арифметические выражения, целые части значений которых определяют номера контрольных буферов файлов (FCB).Эти значения должны принадлежать отрезку [0,15]. Оператор ''CLOSE'' без параметров закрывает //все// открытые ранее файлы. При записи данных оператор ''CLOSE'' обеспечивает вывод в файл,который был открыт ранее в режиме ''FOR OUTPUT'', кода конца файла EOF ("End Of File") с кодом ASCII, равным &h1A. ==== IX.3.2. Операторы PRINT#, PRINT#n, USING. Функции LOF() и LOC() ==== \\ Да,— повторял он себе,— если бы на борту "Пилигрима" я знал все, что должен знать настоящий моряк, сколько несчастий можно было бы избежать! —//Ж.Верн. Дети капитана Гранта// Для формирования строк файла с последовательным доступом используются операторы ''[[#print1|PRINT#]]'' и ''[[#print_using|PRINT#USING]]''. {{anchor:print1}} Оператор ''PRINT#'' записывается в таком виде: ⎧ └─┘ PRINT #n,S ⎨ ; ⎩ , , где: * ''PRINT'' ("печатать", "вывести") — служебное слово; * n — арифметическое выражение, целая часть значения которого определяет номер контрольного буфера файла; * S — список арифметических и (или) строковых выражений: γ1,γ2,… ,γk; * └─┘ — обозначение символа пробел (%%" "%%). При выполнении оператора ''PRINT#'' значение выражения γi (i=1,2,… ,k) последовательно байт за байтом выводится в буфер почти так же, как это делается командой ''PRINT''. Разница состоит лишь в трактовке зонного формата. Если между двумя выражениями в списке S оператора ''PRINT#'' разделителем является //запятая//,то при выводе в буфер соответствующих значений между ними помещается четырнадцать дополнительных пробелов. Если последним символом в операторе ''PRINT#'' является //пробел//, то выполнение оператора ''PRINT#'' приводит к формированию полной строки, но вместе с //меткой// её окончания. Иначе создаётся лишь часть строки, а завершается её формирование или последующими операторами ''PRINT#'', или закрытием файла. Длина строки вместе с концевой меткой не может превысить 256 байтов, а данные выводятся на диск в формате ASCII и только тогда, когда заполняется буфер или закрывается файл. Для экономного размещения данных на диске и избежания ошибок при их считывании целесообразно список S в операторе ''PRINT#'' записывать в виде: ⎧ └─┘ γ1;",";γ2;","; … ;",";γк ⎨ ⎩ ; В этом случае значения в создаваемой строке располагаются в //плотном// формате и отделяются друг от друга запятыми. Будем считать, что информация в одном операторе ''PRINT#'' составляет отдельную логическую строку. Строка разбивается на //поля//. Каждому полю логической строки соответствует переменная из списка S. Так логическая строка, состоящая из трёх полей — фасон одежды S$, цвет одежды C$, цена одежды P — будет выведена в файл оператором PRINT #1,S$;",";C$;",";P ▲ ▲ ▲ │ │ │ Переменные, определяющие поля данной логической строки Если значение какого–либо строкового выражения γi содержит символы "," и (или) ";", то в качестве разделителей можно использовать символ ";", задаваемый строковой функцией ''CHR$(34)'': CHR$(34) γs CHR$(34) {{anchor:e0932-01}} __//Пример 1//__ [[bibliography#b7|[7]]]. Запись данных в файл последовательного доступа. \\ {{.examples:0932-01.bas|}} \\ [[+tab|wmsxbpge>0932-01.bas]] 10 OPEN "GAMES" FOR OUTPUT AS #1 20 FOR X=1 TO 5 30 INPUT"Введите название игры";F$:PRINT #1,F$ 50 NEXT X 60 CLOSE #1 run Введите название игры? Футбол Введите название игры? Гольф Введите название игры? Баскетбол Введите название игры? Хоккей Введите название игры? Регби Ok Если файл с именем "GAMES" уже существовал, то данная программа сотрёт его старое содержимое и будет писать туда заново. Оператор ''PRINT#'', не оканчивающийся символом "," или ";" автоматически порождает печать символа ''CHR$(13)'' (код клавиши 'Ввод '⏎) . Этот символ попадает в буфер и в конце концов в файл, где он служит разделителем между текущей записью и записью, следующей за ней. {{anchor:e0932-02}} __//Пример 2//__ [[bibliography#b5|[5]]]. Открывается новый или ранее созданный файл "Щука" для вывода в него \\ {{.examples:0932-02.bas|}} \\ [[+tab|wmsxbpge>0932-02.bas]] строк от начала. Программная строка 50 позволяет сформировать в буфере одну строку. 20 OPEN "Щука" FOR OUTPUT AS#1 30 A=5:B$="трава":C=83.157 50 PRINT #1,A;",";B$;",";C 60 CLOSE #1 {{anchor:e0932-03}} __//Пример 3//__ [[bibliography#b5|[5]]]. \\ Открывается ранее созданный файл "Шука" для вывода в него строк от конца. Затем программная строка 50 формирует очередные строки файла.По мере заполнения буфера данные выводятся на дискету,а за последней строкой ставится метка окончания файла (EOF). \\ {{.examples:0932-03.bas|}} \\ [[+tab|wmsxbpge>0932-03.bas]] 20 OPEN "Щука" FOR APPEND AS#1 30 INPUT"A=";A:INPUT"B$=";B$:INPUT"C=";C 50 PRINT #1,A;",";B$;",";C 55 IF C<>0 THEN 30 ELSE CLOSE #1 {{anchor:e0932-04}} __//Пример 4//__ [[bibliography#b5|[5]]]. Открывается новый или ранее созданный файл "Карась" для вывода в него строк от начала и далее. Двумя командами 50 и 60 формируется строка. \\ {{.examples:0932-04.bas|}} \\ [[+tab|wmsxbpge>0932-04.bas]] 10 CLEAR 1000:MAXFILES=2:OPEN "Карась" FOR OUTPUT AS#2 30 A$="FLOPPY DISK":E=45:F=54.8 50 PRINT #2,A$;","; '◀── Последний символ ";" ! 60 PRINT #2,E;",";F '◀── Последний символ "пробел" ! 70 CLOSE #2 {{anchor:e0932-05}} __//Пример 5//__ [[bibliography#b5|[5]]]. В файл "Карп" от его начала с клавиатуры вводится S элементов числового массива. \\ {{.examples:0932-05.bas|}} \\ [[+tab|wmsxbpge>0932-05.bas]] 10 MAXFILES=5:OPEN "Карп" FOR OUTPUT AS#4 30 INPUT "Количество элементов";S 40 FOR K=1 TO S:INPUT M:PRINT #4,M;",";:NEXT K 50 CLOSE #4 {{anchor:e0932-06}} __//Пример 6//__ [[bibliography#b5|[5]]]. При формировании строки в качестве разделителей используется символ %%"%%, задаваемый кодом ''CHR$(34)''. \\ {{.examples:0932-06.bas|}} \\ [[+tab|wmsxbpge>0932-06.bas]] 20 OPEN "Сазан" FOR OUTPUT AS#1 30 R=123.789:K$="КRA,,N;W2" 40 I$=CHR$(34) 50 PRINT #1,R;",";I$;K$;I$ 60 CLOSE #1 {{anchor:print_using}} Оператор ''PRINT#,USING'' записывается в таком виде: PRINT #n,USING T,S , где: ''PRINT'', ''USING'' — служебные слова; * T — строковое выражение, значение которого определяет формат вывода; * n — арифметическое выражение, целая часть значения которого определяет номер контрольного буфера файла; * S — список арифметических и (или) строковых выражений: γ1, γ2, …, γk. При выполнении данного оператора значения выражений γi (i=1,2,… ,k) выводятся в соответствии с форматом T в буфер точно так же, как это "делает" "обычный" оператор ''PRINT USING''. {{anchor:e0932-07}} __//Пример 7//__. \\ {{.examples:0932-07.bas|}} \\ [[+tab|wmsxbpge>0932-07.bas]] 10 CLEAR 1000:MAXFILES=5:DIM M(200) 20 OPEN "Лещ" FOR OUTPUT AS#4 30 INPUT"Количество элементов";S 40 FOR K=1 TO S:X=INT(RND(1)*3000)/99:PRINT #4,USING "###.##";X:NEXT K 50 CLOSE #4 Однако следует весьма осторожно употреблять префиксы, обозначающие денежные единицы (%% "$$" %%, %% "**" %% и %% "**$" %%), так как они вызывают форматирование числовых величин как нечисловых. По этой причине числовые величины, снабжённые в дисковом файле такими префиксами, не могут быть считаны оттуда в их исходном виде. {{anchor:e0932-08}} __//Пример 8//__. \\ {{.examples:0932-08.bas|}} \\ [[+tab|wmsxbpge>0932-08.bas]] 10 OPEN "SAMPLE.DAT" FOR OUTPUT AS #1 20 PRINT #1,USING"$$###.##";99.50:CLOSE#1 40 OPEN "SAMPLE.DAT" FOR INPUT AS#1 50 INPUT #1,A:PRINT"Первое значение в файле:";A:CLOSE#1 run Первое значение в файле: 0 Ok Пусть открыт файл B, связанный с буфером FCBn. {{anchor:lof}} Функция LOF(n) , где: * ''LOF'' ("Length Of File" — "размер файла") — служебное слово; * n — арифметическое выражение, целая часть значения которого принадлежит отрезку [0,15] и определяет контрольного буфера файла, соответствующий файлу, возвращает размер файла в байтах. {{anchor:loc}} Функция LOC(n) , где: * ''LOC'' ("LOCation" — "определение позиции") — служебное слово; * n — арифметическое выражение, целая часть значения которого принадлежит отрезку [0,15] и определяет номер контрольного буфера файла, соответствующий файлу, для файлов последовательного доступа возвращает текущее количество байтов информации, считанных в буфер или записанных на дискету. * Или возвращает номер //текущей// номер записи, использованный в последнем выполненном операторе ''[[#PUT]]'' или ''[[#GET]]''. * Для [[#ramdisk|RAM–диска]] возвращает позицию в файле, начиная с номера файла. Например, ''LOC'' возвращает 0 сразу после того, как файл открыт для ввода и вывода (''OPEN FOR INPUT'' / ''OPEN FOR OUTPUT''), и возвращает длину файла сразу после того, как файл открыт для добавления (''OPEN FOR APPEND''). ==== IX.3.3. Операторы INPUT, LINE INPUT#n. Функции INPUT$ и EOF ==== Для чтения строк файла последовательного доступа с дискеты в оперативную память используются операторы ''INPUT#'', ''LINE INPUT#'' и функции ''INPUT$'' и ''EOF''. {{anchor:lineinput}} Оператор LINE INPUT #n,γ , где: * ''LINE'', ''INPUT'' — служебные слова; * n — арифметическое выражение, целая часть значения которого определяет номер контрольного буфера файла; * γ — строковая переменная, позволяет считать очередную строку файла β, связанного с буфером n, и присвоить результат переменной γ. Оператор ''LINEINPUT#'', считывающий одиночное строковое значение, позволяет решить "проблему запятой". {{anchor:e0933-01}} __//Пример 1//__. \\ {{.examples:0933-01.bas|}} \\ [[+tab|wmsxbpge>0933-01.bas]] 10 OPEN "TEST.DAT" FOR OUTPUT AS #1 20 PRINT #1,"Агибалова, Алевтина":CLOSE#1 40 OPEN "TEST.DAT" FOR INPUT AS#1 50 LINE INPUT#1,A$:PRINT"Первое значение в файле:";A$:CLOSE#1 run Первое значение в файле: Агибалова, Алевтина Ok {{anchor:e0933-02}} __//Пример 1//__. \\ {{.examples:0933-02.bas|}} \\ [[+tab|wmsxbpge>0933-02.bas]] 10 CLEAR 1000:MAXFILES=5:DIM M(200) 20 OPEN "LINP" FOR OUTPUT AS#4 30 INPUT"Количество элементов";S 40 FOR K=1 TO S:PRINT #4,K;",";:PRINT LOC(4);:NEXT K:CLOSE #4 70 OPEN "LINP" FOR INPUT AS#4 80 PRINT:PRINT LOF(4) 90 LINE INPUT #4,M$ 100 PRINT LOC(4),:PRINT M$ 110 IF NOT EOF(4) THEN 90 'Обратите внимание на данную строку! 120 PRINT LOF(4):CLOSE #4 {{anchor:input}} Оператор ''INPUT#'' записывается в виде: INPUT #n,S , где: * ''INPUT'' — служебное слово; * n — арифметическое выражение, целая часть значения которого определяет номер контрольного буфера файла; * S — список переменных. Опишем, как происходит выполнение этого оператора. Если очередная считываемая строка файла состоит из значений: α1, α2, …, αk, то в соответствующей команде ''INPUT#'' список S должен иметь такой вид: β1, β2, …, βk, а каждая переменная βi обязана быть того же типа,что и значение αi. В этом случае выполнение оператора приводит к присваиваниям переменным βi значений αi. {{anchor:e0933-03}} __//Пример 3//__. Чтение из файла последовательного доступа. \\ {{.examples:0933-03.bas|}} \\ [[+tab|wmsxbpge>0933-03.bas]] 10 OPEN "GAMES" FOR INPUT AS #2 20 FOR X=1 TO 5:INPUT #2,G$:PRINT G$:NEXT X:CLOSE #2 run Футбол Гольф Баскетбол Хоккей Регби Ok {{anchor:e0933-04}} __//Пример 4//__. \\ {{.examples:0933-04.bas|}} \\ [[+tab|wmsxbpge>0933-04.bas]] 10 OPEN "SAMPLE.DAT" FOR OUTPUT AS #1 20 PRINT #1,12,567:CLOSE#1 40 OPEN "SAMPLE.DAT" FOR INPUT AS#1 50 INPUT #1,A,B:PRINT"Второе значение в файле:";B:CLOSE#1 run Второе значение в файле: 567 Ok {{anchor:e0933-05}} __//Пример 5//__. \\ {{.examples:0933-05.bas|}} \\ [[+tab|wmsxbpge>0933-05.bas]] 10 OPEN "TEST.DAT" FOR OUTPUT AS #1 20 PRINT #1,"Кремний";14;28.0855:CLOSE#1 40 OPEN "TEST.DAT" FOR INPUT AS#1 50 FOR K%=1 TO 3:INPUT#1,A$:PRINT"Значение номер";K%;":";A$:NEXT K% 70 CLOSE#1 run Значение номер 1: Кремний 14 28.0855 Input past end in 50 Ok При выполнении оператора ''PRINT#'' (строка 20) в файл записываются три различных значения, но поскольку в операторе они разделяются символами «;», в файл они будут заноситься без разделителей. Когда оператор ''INPUT#'' реализует считывание этих значений (строка 50), они все "сливаются" в одно. Таким образом, в файле не будет существовать ни второго, ни третьего значений, поэтому при попытке чтения программой какой-либо информации за последним значением в файле фиксируется ошибка "Считывание за пределами последнего значения". Разделителем для строковых данных может быть запятая или символ "Возврат каретки". Те же самые знаки или пробелы служат для разграничения числовых величин. Существует несколько способов гарантированной расстановки разделителей между отдельными значениями. Один из самых простых состоит в том, чтобы присвоить значение "," строковой переменной и записывать её после каждого значения в операторе ''PRINT#''. {{anchor:e0933-06}} __//Пример 6//__. \\ {{.examples:0933-06.bas|}} \\ [[+tab|wmsxbpge>0933-06.bas]] 10 OPEN "TEST.DAT" FOR OUTPUT AS #1 15 D$=",":PRINT#1,"Кремний";D$;14;D$;28.0855:CLOSE#1 40 OPEN "TEST.DAT" FOR INPUT AS#1 50 FOR K%=1 TO 3:INPUT #1,A$:PRINT"Значение номер";K%;":";A$:NEXT K% 70 CLOSE#1 run Значение номер 1: Кремний Значение номер 2: 14 Значение номер 3: 28.0855 Ok Отметим, что строковая величина в дисковом файле, могущая содержать запятую, должна быть записана в кавычках; оператор ''INPUT#'' обеспечивает устранение этих кавычек при считывании. {{anchor:e0933-07}} __//Пример 7//__. \\ {{.examples:0933-07.bas|}} \\ [[+tab|wmsxbpge>0933-07.bas]] 10 OPEN "TEST.DAT" FOR OUTPUT AS #1 20 PRINT#1,CHR$(34);"Манагуа, Никарагуа";CHR$(34):CLOSE#1 40 OPEN "TEST.DAT" FOR INPUT AS#1 50 INPUT#1,A$:PRINT"Первое значение в файле:";A$:CLOSE#1 run Первое значение в файле: Манагуа, Никарагуа Ok {{anchor:e0933-08}} __//Пример 8//__ [[bibliography#b7|[7]]]. //Обновление// файла последовательного доступа. \\ {{.examples:0933-08.bas|}} \\ [[+tab|wmsxbpge>0933-08.bas]] 10 OPEN "GAMES" FOR INPUT AS #1 'Открывается "старый" файл 20 OPEN "GAMES2" FOR OUTPUT AS #2 'Открывается "новый" файл (пустой) 30 FOR X=1 TO 5 40 INPUT #1,F$ 50 IF F$="Баскетбол" THEN F$="Водное поло" 60 PRINT #2,F$ 70 NEXT X 80 CLOSE 1,2 'Оба файла закрываются 90 KILL"GAMES" 'Удаление исходного файла 100 NAME "GAMES2" AS "GAMES" 'Переименование "нового" файла {{anchor:e0933-09}} __//Пример 9//__. \\ {{.examples:0933-09.bas|}} \\ [[+tab|wmsxbpge>0933-09.bas]] 10 CLEAR 1000:MAXFILES=5:DIM M(200) 20 OPEN "Шар" FOR OUTPUT AS#4:INPUT"Количество элементов";S 40 FOR K=1 TO S 50 X=RND(1):Y=RND(1) 60 X$=CHR$(INT(RND(1)*31)+224):Y$=CHR$(INT(RND(1)*31)+224) 70 PRINT #4,X$+Y$;",";X;",";Y; 80 NEXT K:CLOSE #4 90 OPEN "Шар" FOR INPUT AS#4 100 INPUT #4,M$,A,B:PRINT M$;A,B 120 IF NOT EOF(4) THEN 100 130 CLOSE #4 run Количество элементов? 5 ВЯ .59521943994623 .10658628050158 КЩ .73474759503023 .18426812909758 ЫО .63799556899423 .47041117641358 ОВ .18586284343823 .12951037284958 ТМ .02818381196223 .48775999680558 Ok Заметим, что строка 100 в этом примере могла быть заменена на один из фрагментов: а) 100 INPUT #4,M$ 101 INPUT #4,A,B b) 100 INPUT #4,M$ 101 INPUT #4,A 102 INPUT #4,B {{anchor:input1}} Для чтения очередного фиксированного количества символов из файла без учёта его разбиения на строки используется функция INPUT$(m[,[#]n]) , где: * ''INPUT$'' — служебное слово; * m — арифметическое выражение, целая часть значения которого должна принадлежать отрезку [1,255]; * n — номер контрольного буфера файла. В любой момент работы с файлом функция ''INPUT$'' "читает" INT(m) его очередных символов. Иными словами, последовательность этих символов становится значением функции ''INPUT$()''. При этом метки окончания строк воспринимаются так же, как любые другие символы. Функция ''INPUT$'' возвращает строку, содержащую заданное количество символов, прочитанных из файла. Все символы, включая разделители, передаются в программу, за исключением специального символа с кодом ASCII &H1A, который воспринимается как признак конца файла и "прекращает выполнение" функции. Функция ''INPUT$'' предоставляет возможность последовательно выбирать символы из файла независимо от разделителей строк! Для полного уяснения семантики функции ''INPUT$'' рекомендуется "прогнать" следующий пример при различных значениях параметров S и X. {{anchor:e0933-10}} __//Пример//__10 [[bibliography#b5|[5]]]. \\ {{.examples:0933-10.bas|}} \\ [[+tab|wmsxbpge>0933-10.bas]] 10 CLEAR 1000:MAXFILES=5:DIM M(200) 20 OPEN "ТОР" FOR OUTPUT AS#4 30 INPUT "Количество элементов";S 40 FOR K=1 TO S:PRINT #4,"L";",";"W";",":NEXT K:CLOSE #4 70 OPEN "ТОР" FOR INPUT AS#4 80 INPUT"Длина значения в INPUT$";X 90 Y=(LOF(4)-1)/X: Z=(LOF(4)-1)MOD X 105 IF Y=0 THEN 130 106 FOR K=1 TO Y 110 X$=INPUT$(X,#4):PRINT X$ 115 NEXT 120 IF Z=0 THEN 140 130 PRINT INPUT$(Z,#4) 140 CLOSE #4 Заметим, что "длину" файла не всегда можно определить заранее: представьте себе файл адресов, который все время приходится открывать в режиме добавления данных (''FOR APPEND''). Функция ''EOF'' позволяет вам решить эту проблему: специальный символ с кодом &h1А добавляется к концу файла, когда этот файл закрывается. Этот символ помечает //конец// файла. {{anchor:eof}} Функция ''EOF'', синтаксис которой EOF(n) , где: * ''EOF'' ("End Of File" — "конец файла") — служебное слово; * n — арифметическое выражение, целая часть значения которого определяет номер файла, сравнивает код очередного символа с кодом &h1А и возвращает: * -1 ("true"), если найден код конца файла, и * 0 ("false") в противном случае. {{anchor:e0933-11}} __//Пример 11//__. Продемонстрируем способ использования функции ''EOF()''. \\ {{.examples:0933-11.bas|}} \\ [[+tab|wmsxbpge>0933-11.bas]] 10 OPEN "TESTF" FOR INPUT AS #1 20 IF EOF(1) THEN 60 30 INPUT #1,A:PRINT A:GOTO 20 60 CLOSE #1 Ниже приведены 3 схемы, определяющие последовательность операций, которые должны быть выполнены при перемещениях строк файлов //последовательного доступа// из оперативной памяти на дискету и в обратном направлении. - Общая схема формирования строк на диске от //начала// файла В: * А. В оперативной памяти резервируется буфер (оператором ''MAXFILES=''). * B. Открывается новый или уже существующий файл В (оператором ''OPEN'' с параметром ''OUTPUT''). * C. Формируется требуемое количество строк файла(операторами ''PRINT#'' или ''PRINT#,USING''). На дискету из буфера они сбрасываются автоматически. * D. Файл В закрывается. {{anchor:e0933-12}} __//Пример 12//__ [[bibliography#b7|[7]]]. \\ {{.examples:0933-12.bas|}} \\ [[+tab|wmsxbpge>0933-12.bas]] 10 OPEN "DRESS" FOR OUTPUT AS #1 20 FOR X=1 TO 5 30 INPUT"Данные об одежде";S$,C$,P:PRINT #1,S$;",";C$;",";P 50 NEXT X:CLOSE #1 run Данные об одежде? А35,Красный,68.95 Данные об одежде? A36,Голубой,75 Данные об одежде? Б44,Розовый,105.50 Данные об одежде? В78,Серый,85 Данные об одежде? ЖД5,Черный,78.89 Ok Отдельные сегменты программных файлов — это специфические файлы данных последовательного доступа. Поэтому программы или их фрагменты можно загружать в память как данные. Ограничимся здесь лишь двумя примерами. {{anchor:e0933-13}} //Пример 13//. Выполнение этой программы приводит к считыванию и выводу на экран всех строк программы "Симпсон". \\ {{.examples:0933-13.bas|}} \\ [[+tab|wmsxbpge>0933-13.bas]] 10 'Чтение программного файла 20 OPEN "Симпсон" FOR INPUT AS#1 30 LINE INPUT #1,R$:PRINT R$ 50 IF NOT EOF(1) THEN 30 60 CLOSE #1 {{anchor:e0933-14}} //Пример 14//. Выполнение программы даёт возможность "просмотреть" в той же самой программе "Симпсон" строки с номерами от 30 и до 70. \\ {{.examples:0933-14.bas|}} \\ [[+tab|wmsxbpge>0933-14.bas]] 10 'Чтение диапазона строк 20 OPEN "Симпсон" FOR INPUT AS#1 30 LINE INPUT #1,R$ 40 X$=MID$(R$,1,2) 50 IF X$<"30" OR X$>"70" THEN 80 60 PRINT R$ 80 IF NOT EOF(1) THEN 30 90 CLOSE #1 - Общая схема пополнения файла В строками с его //конца//: * А. В оперативной памяти резервируется буфер (оператором MAXFILES=). * B. Открывается уже открытый файл В (оператором OPEN с параметром APPEND). * C. Формируется требуемое количество строк файла(операторами PRINT# или ''PRINT#,USING''). На дискету из буфера они сбрасываются автоматически. * D. Файл В закрывается. {{anchor:e0933-15}} __//Пример 15//__ [[bibliography#b7|[7]]]. Добавление в файл спортивной информации названия двух новых видов спорта. \\ {{.examples:0933-15.bas|}} \\ [[+tab|wmsxbpge>0933-15.bas]] 10 OPEN "GAMES" FOR APPEND AS#1 20 PRINT #1,"Пинг-понг":PRINT #1,"Теннис":CLOSE #1 - Общая схема //считывания// строк с диска от начала файла В * А. В оперативной памяти резервируется буфер (оператором ''MAXFILES'') * В. Открывается уже существующий файл В (оператором ''OPEN'' с параметром ''INPUT'') * C. Считывается требуемое количество строк файла(операторами ''INPUT$'' или ''LINEINPUT$'', или ''INPUT$'') * D. Файл В закрывается {{anchor:e0933-16}} __//Пример 16//__ [[bibliography#b7|[7]]]. \\ {{.examples:0933-16.bas|}} \\ [[+tab|wmsxbpge>0933-16.bas]] 10 OPEN "DRESS" FOR INPUT AS#2 20 FOR X=1 TO 5 30 INPUT #2,S$,C$,P:PRINT S$,C$,P 50 NEXT X:CLOSE #2 run А35 Красный 68.95 A36 Голубой 75 Б44 Розовый 105.50 В78 Серый 85 ЖД5 Черный 78.89 Ok ==== IX.3.4. Примеры ==== - {{anchor:e0934-01}} Гидрометцентр ведёт статистику выпадения снега по регионам, для каждого из которых заведён файл последовательного доступа.Во всех файлах имеется по три элемента данных: имя метеоролога, название региона, количество выпавшего за зиму снега в мм. * Напишите программу ввода данных; заполните файлы для трёх регионов. * Просмотрите все три файла и подсчитайте средний уровень снежных осадков по трём регионам. Результат выведите на экран. \\ {{.examples:0934-01.bas|}} \\ [[+tab|wmsxbpge>0934-01.bas]] 10 MAXFILES=6:OPEN "region1" FOR OUTPUT AS #1 21 OPEN "region2" FOR OUTPUT AS #2:OPEN "region3" FOR OUTPUT AS #3 30 FOR I=1 TO 3 31 PRINT "region";I 35 INPUT "Введите количество работающих метеорологов на станции";N 36 FOR E=1 TO N 40 INPUT "Введите:имя метеоролога";I$:INPUT "название региона";R$:INPUT "количество выпавшего за зиму снега в мм";K 50 PRINT #I,I$;",";R$;",";K 55 NEXT E 60 CLOSE #I 70 NEXT I:CLS 71 OPEN "region1" FOR INPUT AS #1:OPEN "region2" FOR INPUT AS #2 73 OPEN "region3" FOR INPUT AS #3 80 FOR O=1 TO 3 90 S=0 100 FOR E=1 TO N:INPUT #O,I$,R$,K:S=S+K:NEXT E 140 S=S/N:PRINT"Средний уровень снежных осадков по ";R$;" региону";S 150 CLOSE #O 160 NEXT O 170 END - {{anchor:e0934-01}} Хоккейные команды "Чёрные ястребы" и "Красные крылья" хранят в файлах последовательного доступа имена всех своих 12 нападающих, число заброшенных ими шайб, сделанных голевых передач и заработанное штрафное время. * Создайте файлы "BLACK" и "RED", содержащие информацию о каждой из двух команд. * Ваша программа по данным, извлечённым из этих файлов, должна порождать новый файл "ALLSTARS", в котором содержались бы имя, команда и сумма очков (голы + передачи) для шести лучших игроков обеих команд. Выведите имена и показатели результативности хоккеистов на экран дисплея. ]\ {{.examples:0934-02.bas|}} \\ [[+tab|wmsxbpge>0934-02.bas]] 10 MAXFILES=3 20 OPEN "BLACK" FOR OUTPUT AS #1:OPEN "RED" FOR OUTPUT AS #2 25 FOR K=1 TO 2 30 FOR X=1 TO 6 'В каждой команде - 6 игроков 40 PRINT "Данные о команде";K;":" 50 INPUT "Имя нападающего";I$:INPUT "Число заброшенных шайб";F:INPUT "Сделанных голевых передач";G:INPUT "Заработанное штрафное время";W 60 PRINT #K,I$;",";F;",";G;",";W 70 NEXT X 80 CLOSE #K 81 NEXT K 90 OPEN "BLACK" FOR INPUT AS #1:OPEN "RED" FOR INPUT AS #2 100 OPEN "ALLSTARS" FOR OUTPUT AS #3 110 DIM MI$(12):DIM MK$(12):DIM MO(12) 115 I=1 120 FOR K=1 TO 2 130 FOR X=1 TO 6 140 INPUT #K,I$,F,G,W 145 IF K=1 THEN A$="BLACK" ELSE A$="RED" 150 O=F+G:MI$(I)=I$:MK$(I)=A$:MO(I)=O:I=I+1 155 NEXT X 156 CLOSE #K 157 NEXT K 165 FOR I=1 TO 11 166 L=I 170 FOR J=I+1 TO 12 175 IF MO(L) - {{anchor:e0934-02}} Помогите декану факультета организовать файл академических занятий студентов, для чего: * создайте файл последовательного доступа и заполните его именами студентов, названиями академических курсов и оценками;при этом воспользуйтесь следующими данными: ^ Имя студента ^ Академический курс ^ Отметка ^ |Сергей| Французский язык | 5 | |Дмитрий| Английский язык | 4 | |Олег | Математика | 5 | |Борис| Французский язык | 3 | |Михаил| Английский язык | 3 | |Александр| Математика | 5 | |Тимофей| Математика | 4 | * выберите "умных" студентов, т.е. тех, кто имеет оценку выше 4,и запишите сведения о них в файл "SMART"; * пусть программа помогает декану формировать на основе этого файла группы углублённого обучения.По названию курса она должна выдавать список "умных" студентов, зачисленных в такую группу. \\ {{.examples:0934-03.bas|}} \\ [[+tab|wmsxbpge>0934-03.bas]] 10 MAXFILES=2:INPUT "Количество студентов";N 20 OPEN "СПИСОК" FOR OUTPUT AS #1:OPEN "SMART" FOR OUTPUT AS #2 30 FOR X=1 TO N 50 INPUT"Ф.И. студента:";I$:INPUT"Название курса:";K$:INPUT"Оценка:";O 60 PRINT #1,I$;",";K$;",";O 70 NEXT X:CLOSE #1 90 OPEN "СПИСОК" FOR INPUT AS #1 130 FOR X=1 TO N 140 INPUT #1,I$,K$,O:IF O>=4 THEN D=D+1:PRINT #2,I$;",";K$ 155 NEXT X:CLOSE #1:CLOSE #2 220 OPEN "SMART" FOR INPUT AS#2 225 INPUT "Введите название курса";E$ 230 FOR I=1 TO D 240 INPUT #2,I$,K$:IF K$=E$ THEN PRINT I$ 280 NEXT I:CLOSE #2 290 PRINT "Хотите закончить Д/Н" 300 IF INPUT$(1)="Д" THEN END ELSE GOTO 220 {{anchor:open}} ==== IX.3.5. Вывод файлов данных на экран и принтер ==== Текстовые экраны 0 и 1, графические экраны, а также принтер могут быть объявлены устройствами вывода файлов последовательного доступа. //Открытие// таких файлов осуществляется оператором ⎧ "CRT:" OPEN ⎨ "GRP:" FOR OUTPUT AS[#]n ⎩ "LPT:" , где: * ''OPEN'', ''FOR'' ''OUTPUT'', ''AS'' — служебные слова; * n — арифметическое выражение, целая часть значения которого определяет номер контрольного буфера файла; * ''CRT:'', ''GRP:'', ''LPT:'' — имена устройств. При выполнении оператора ''OPEN'' в качестве устройства вывода файлов назначаются: //текстовые// экраны (''CRT:''), //графические// экраны (''GRP:''), //принтер// (''LPT:''). Вывод строк в любом случае осуществляется операторами ''PRINT#'' и ''PRINT#,USING''. Поговорим о выводе //программных// файлов на экран и принтер. Используя устройства ''CRT:'', ''GRP:'' и ''LPT:'', можно выводить текст программы на экран и принтер. - Команда ''%%SAVE "LPT:"%%'' предназначена для вывода текста программы на //принтер//. - Команда ''%%SAVE "CRT:"%%'' позволяет выводить текст программы на //текстовый// экран. - Команда ''%%SAVE "GRP:"%%'' позволяет выводить текст программы на //графический// экран. Использование "графического" оператора ''%%SAVE "GRP:"%%'' в текстовом режиме приводит к сообщению об ошибке: "Illegal function call". Вполне естественно, что команды ''LOAD'', ''RUN'' и ''MERGE'' не могут "работать" с устройствами ''CRT:'', ''GRP:'' и ''LPT:'' ! __//Примеры//__: - {{anchor:e0935-01}} {{.examples:0935-01.bas|}} \\ [[+tab|wmsxbpge>0935-01.bas]] 10 COLOR 1,11,7:SCREEN 2:OPEN "GRP:" FOR OUTPUT AS#1 30 PSET (69,80):PRINT #1,"Текст на графическом экране SCREEN 2" 50 GOTO 50 - {{anchor:e0935-02}} {{.examples:0935-02.bas|}} \\ [[+tab|wmsxbpge>0935-02.bas]] 10 COLOR 1,11,7:SCREEN 3:OPEN "GRP:" FOR OUTPUT AS#1 30 PSET (50,80):PRINT #1,"Текст на графическом экране SCREEN 3" 50 GOTO 50 - FIXME {{anchor:e0935-03}} Программа "777", записанная на диске в формате ASCII, выводится на графический экран: \\ {{.examples:0935-03.bas|}} \\ [[+tab|wmsxbpge>0935-03.bas]] 10 COLOR 1,15,8:SCREEN 3:PSET(0,10),15:MAXFILES=2 30 OPEN "GRP:" FOR OUTPUT AS#1:OPEN "777" FOR OUTPUT AS#2 50 LINE INPUT #2,R$:PRINT #1,R$ 80 IF NOT EOF(2) THEN 50 90 CLOSE:GOTO 90 - FIXME {{anchor:e0935-04}} Файл данных последовательного доступа, записанный на дискете под именем "КАРП", выводится на принтер. \\ {{.examples:0935-04.bas|}} \\ [[+tab|wmsxbpge>0935-04.bas]] 15 MAXFILES=2 18 OPEN "Карп" FOR OUTPUT AS#1:OPEN "LPT:" FOR OUTPUT AS#2 30 INPUT #1,M:PRINT #2,M; 35 IF NOT EOF(1) THEN 30 {{anchor:e0935-05}} __//Пример 5//__ [[bibliography#b76|[76]]]. Простейший //графический// редактор. При формировании изображения вам могут понадобиться такие команды: * L При нажатии этой клавиши определяется начальная точка прямой. При повторном нажатии вычерчивается прямая. * P Закрашивается участок экрана. * U Отменяется последняя команда. * DEL Уничтожается программа, запущенная из памяти, а экран очищается. * ESC Генерируется программа. После окончания формирования изображения текст программы на языке [[msx:basic:]] можно вызвать на экран, либо записать на ленту или дискету (по команде ''SAVE''. При необходимости программу с ленты или с дискеты можно вновь загрузить (командой ''LOAD'') или "слить" с другой программой, хранящейся в памяти (командой ''MERGE''). Один из спрайтов задействуется как курсор, другой — в качестве маркера, отмечающего начало прямой, и ещё шесть в качестве "координатных", чтобы отмечать текущие координаты курсора на экране. Когда курсор "касается" одного из "координатных" спрайтов, они пропадают. Это выполняется с использованием прерывания по ''ON SPRITE GOSUB''. \\ FIXME {{.examples:0935-05.bas|}} \\ [[+tab|wmsxbpge>0935-05.bas]] 10 GOTO 210 30 'Изображение дополнительных координат 40 ' (подпрограмма) 60 PUT SPRITE 0,(16,P),1,H 70 PUT SPRITE 1,(22,P),1,T 80 PUT SPRITE 2,(28,P),1,U 90 PUT SPRITE 3,(16,P+8),1,H1 100 PUT SPRITE 4,(22,P+8),1,T1 110 PUT SPRITE 5,(28,P+8),1,U1 120 RETURN 130 ' О с н о в н а я программа 210 SCREEN 0:KEY OFF:WIDTH 38 220 DEFINT A-Z 230 MAXFILES=2 240 DIM BUF(100,5) 260 ' Открытие файла 280 PRINT"ЭКРАННЫЙ ГЕНЕРАТОР" 290 PRINT 300 PRINT"Включите на всякий случай принтер!" 310 PRINT:PRINT 320 PRINT"Введите имя файла:"; 330 A$=INPUT$(1) 340 IF A$=CHR$(13) AND F$<>""THEN 390 350 IF A$=CHR$(8) AND POS(0)-1>16 THEN LOCATE POS(0)-1:PRINT CHR$(32);:LOCATE POS(0)-1:F$=LEFT$(F$,LEN(F$)-1):GOTO 330 360 IF LEN(F$)=6 THEN GOTO 330 370 IF (A$>="A"AND A$<="Z")OR (A$>="a" AND A$<="z")THEN F$=F$+A$ ELSE GOTO 330 380 PRINT A$;:GOTO 330 390 PRINT:PRINT 400 PRINTUSING"Открывается файл:&";F$ 410 PRINT:PRINT 420 OPEN F$ FOR OUTPUT AS#2 430 PRINT USING"Файл'&'Открыт";F$ 440 PRINT:PRINT 450 PRINT"Для продолжения нажмите любую клавишу" 460 A$=INPUT$(1) 470 SCREEN 2,0,0 480 GOSUB 800 490 IX=-1:P=8:Q=168:X=128:Y=96 500 H=1:T=2:U=8:H1=0:T1=9:U1=6 510 MX=1:MY=1:HX=8:HY=8:LX=0:LY=0 520 ON SPRITE GOSUB 1780:SPRITE ON 530 PUT SPRITE 6,(X,Y),1,10 540 GOSUB 60 550 A$=INKEY$:IF A$=""THEN 550 560 IF A$=CHR$(127)THEN IX=-1:CLS 570 IF A$=CHR$(27)THEN GOTO 1320 580 IF A$="P"THEN GOSUB 910 590 IF A$="L"THEN GOSUB 1000 600 IF A$="U"THEN GOSUB 1160 610 D=STICK(0):IF D=0 THEN 550 620 IF D=1 THEN Y=Y-MY 630 IF D=2 THEN Y=Y-MY:X=X+MX 640 IF D=3 THEN X=X+MX 650 IF D=4 THEN X=X+MX:Y=Y+MY 660 IF D=5 THEN Y=Y+MY 670 IF D=6 THEN Y=Y+MY:X=X-MX 680 IF D=7 THEN X=X-MX 690 IF D=8 THEN X=X-MX:Y=Y-MY 700 IF X>255 THEN X=255 710 IF Y>191 THEN Y=191 720 IF X<0 THEN X=0 730 IF Y<0 THEN Y=0 740 H=INT(X/100):T=(XMOD100)/10:U=X MOD10 750 H1=INT(Y/100):T1=(YMOD100)/10:U1=Y MOD10 760 GOTO 530 780 ' О п и с а н и е спрайтов 800 FOR I=0 TO 11 810 S$="" 820 FOR J=1 TO 8 830 READ A$:S$=S$+CHR$(VAL("&h"+A$)) 840 NEXT 850 SPRITE$(I)=S$ 860 NEXT 870 RETURN 890 ' Подпрограмма закраски 910 IF POINT(X,Y)=15 THEN RETURN 920 IF IX+1=500 THEN RETURN 930 IX=IX+1 940 PAINT(X,Y) 950 BUF(IX,0)=1:BUF(IX,1)=X:BUF(IX,2)=Y 960 RETURN 980 ' Изображение п р я м о й 1000 IF L=0 THEN 1070 1010 L=0 1020 LINE(X,Y)-(BUF(IX,1),BUF(IX,2)) 1030 IF(X=BUF(IX,1))AND(Y=BUF(IX,2))THEN BUF(IX,0)=2:PUT SPRITE 7,(0,209):SPRITE ON:RETURN 1040 BUF(IX,3)=X:BUF(IX,4)=Y 1050 PUT SPRITE 7,(0,209) 1060 BUF(IX,0)=3:SPRITE ON:RETURN 1070 IF IX+1=100 THEN RETURN 1080 IX=IX+1 1090 L=1:SPRITE OFF 1100 BUF(IX,1)=X:BUF(IX,2)=Y 1110 PUT SPRITE 7,(X-1,Y-2),1,11 1120 RETURN 1140 'Отмена предыдущего действия 1160 IX=IX-1 1170 CLS 1180 IF IX<=-1 THEN IX=-1:BUF(0,0)=0:RETURN 1190 FOR I=0 TO IX 1200 ON BUF(I,0) GOSUB 1230,1250,1270 1210 NEXT 1220 RETURN 1230 PAINT(BUF(I,1),BUF(I,2)) 1240 RETURN 1250 PSET(BUF(I,1),BUF(I,2)) 1260 RETURN 1270 LINE(BUF(I,1),BUF(I,2))-(BUF(I,3),BUF(I,4)) 1280 RETURN 1300 'Генерация программы 1320 SPRITE OFF:SCREEN 0'В оригинале оператор SPRITE OFF отсутствует! 1330 PRINT"Вывод на принтер(P)" 1340 PRINT"Вывод на экран(S)" 1350 PRINT:PRINT 1360 PRINT"Выбирайте скорее режим:" 1370 LOCATE 23,4 1382 A$=INPUT$(1) 1390 PRINT A$ 1400 IF A$<>"P"ANDA$<>"S" THEN BEEP:GOTO 1370 1410 IF A$="P"THEN OPEN"LPT:"AS#1 1420 IF A$="S"THEN OPEN"CRT:"AS#1 1430 CLS 1450 'З а п и с ь п р о г р а м м ы 1470 FOR D=1 TO 2 1480 PRINT#D,"10 REM*" 1490 PRINT#D,USING"20 REM*Имя программы:&";F$ 1500 PRINT#D,"30 REM*" 1510 PRINT#D,"40 SCREEN 2" 1520 LN=50 1530 FOR I=0 TO IX 1540 PRINT#D,MID$(STR$(LN),2);SPC(1) 1550 ON BUF(I,0)GOSUB 1610,1650,1690 1560 LN=LN+10 1570 NEXT 1580 PRINT#D,MID$(STR$(LN),2);SPC(1);"GOTO";MID$(STR$(LN),2) 1590 NEXT 1600 END 1610 T$=MID$(STR$(BUF(I,1)),2) 1620 U$=MID$(STR$(BUF(I,2)),2) 1630 PRINT#D,USING"PAINT(&,&)";T$;U$ 1640 RETURN 1650 T$=MID$(STR$(BUF(I,1)),2) 1660 U$=MID$(STR$(BUF(I,2)),2) 1670 PRINT#D,USING"PSET(&,&)";T$;U$ 1680 RETURN 1690 T$=MID$(STR$(BUF(I,1)),2) 1700 U$=MID$(STR$(BUF(I,2)),2) 1710 V$=MID$(STR$(BUF(I,3)),2) 1720 W$=MID$(STR$(BUF(I,4)),2) 1730 PRINT#D,USING"LINE(&,&)-(&,&)";T$;U$,V$,W$ 1740 RETURN 1760 'Подпрограмма обработка прерываний 1780 SPRITE OFF 1790 SWAP P,Q 1800 GOSUB 60 1810 FOR D=1 TO 100:NEXT 1820 SPRITE ON 1830 RETURN 1840 DATA 70,88,98,A8,C8,88,70,0 1850 DATA 20,60,20,20,20,20,70,0 1860 DATA 70,88,08,30,40,80,F8,0 1870 DATA F8,08,10,30,08,88,70,0 1880 DATA 10,20,50,90,F8,10,10,0 1890 DATA F8,80,F0,08,08,88,70,0 1900 DATA 38,40,80,F0,88,88,70,0 1910 DATA F8,08,10,20,40,40,40,0 1920 DATA 70,88,88,70,88,88,70,0 1930 DATA 70,88,88,78,08,10,E0,0 1940 DATA 80,40,20,10, 8, 4, 2,1 1950 DATA 40,E0,40, 0, 0, 0, 0,0 {{anchor:n94}} {{anchor:ramdisk}} ===== IX.4. Использование RAM–диска (только для компьютеров MSX 2) ===== \\ RAMdisk (псевдодиск) — логическое устройство, обеспечивающее хранение файлов в специально выделенной области оперативной памяти.Используется на микроЭВМ и ПЭВМ. —//Англо–русский словарь по программированию и информатике// Свободное пространство памяти, размер которого можно определить при помощи функций ''FRE(0)'' и ''FRE(%%""%%)'', автоматически распределяется интерпретатором [[msx:basic:]]. Когда программа слишком длинна или использует слишком много переменных, для временного хранения данных следует использовать либо внешние устройства (магнитные ленты, дискеты), либо дополнительную область памяти MSX–компьютера (так называемый RAM //диск//). Эта дополнительная область не распределяется //автоматически// т.е. если программа, например, использует слишком много переменных, это ещё не значит, что значения этих переменных будут автоматически перенесены в дополнительную область оперативной памяти! Вы сейчас убедитесь в том, что доступ к этой области осуществляется аналогично доступу к //дисководам// ! {{anchor:callmemini}} Оператор CALL MEMINI [(R)] , где: * ''CALL'' ("вызвать"), ''MEMINI'' ("MEMory INIcialisation" — "инициализация памяти") — служебные слова; * R — арифметическое выражение, целая часть значения которого принимает значения от 6655 до M-32769, где M — максимальный объем RAM, инициализирует RAM диск и сообщает его текущий свободный объем. Этот оператор должен быть выполнен до первой попытки обращения к RAM диску. Помните, что это обращение //уничтожает// все файлы, записанные до этого на RAM диск. Отметим, что для MSX–компьютеров с общим объёмом RAM в 128 Кбайт значение параметра R не должно превышать 98303 байт. Фактический же размер RAM диска (в байтах) равен значению арифметического выражения R-6399 . Если значение параметра R меньше указанного минимального значения, то RAM диск "отключается" и компьютер выдаёт сообщение: "No RAM disk", если же значение параметра R больше максимального значения, то появляется сообщение о неправильном вызове функции "Illegal function call". Когда параметр R опущен, то его значение по умолчанию устанавливается равным максимальному, т.е. 98303-6399 = 91904 ≈ 92 Кбайта. Параметр R необходим, если Вы хотите использовать дополнительные области RAM как для временного хранения файлов, так и для других целей. Если же это не так, то используйте команду CALL MEMINI . //Имена// файлов, находящихся на RAM диске, должны включать: - имя устройства "МЕМ:", - имя файла, состоящее не более чем из 8 символов (причём символы "*" и "?" не могут использоваться!), и - расширение имени файла, состоящее из точки и не более чем из 3–х символов. Впрочем, расширение имени файла не обязательно; если оно пропущено, то точка также может быть опущена. Например: МЕМ:PROGRAM1.BAS MEM:HRU Команды для работы с RAM диском очень похожи на команды ''FILES'', ''KILL'' и ''NAME'' версии [[msx:disk_basic]]. {{anchor:callmfiles}} 1) Команда CALL MFILES , где: ''CALL'', ''MFILES'' — служебные слова; выводит на экран список файлов, записанных на RAM диске, и размер оставшегося свободного пространства. {{anchor:callmkill}} 2) Команда CALL MKILL ("Имя файла") , где: ''CALL'', ''MKILL'' — служебные слова; "стирает" файл с указанным именем с RAM диска. Обратите внимание на то, что параметр %%"%%Имя файла%%"%% заключается в круглые скобки! {{anchor:callmname}} 3) Команда CALL MNAME ("Имя старого файла" AS "Имя нового файла") , где: * ''CALL'', ''MNAME'' — служебные слова; * параметр %%"Имя старого файла"%% обязательно должен присутствовать, параметр %%"Имя нового файла"%% может быть опущен; позволяет изменить имя файла. Перечислим теперь операторы и функции, которые можно использовать для работы с программными файлами и с файлами //последовательного// доступа: * ''[[009#save|SAVE]]'' * ''[[009#load|LOAD]]'' * ''[[009#merge|MERGE]]'' * ''[[009#run|RUN]]'' * ''[[009#open|OPEN]]'' * ''[[009#close|CLOSE]]'' * ''[[009#print1|PRINT #]]'' * ''[[009#print_using|PRINT #,USING]]'' * ''[[009#input|INPUT#]]'' * ''[[009#input1|INPUT$]]'' * ''[[009#lineinput|LINE INPUT #]]'' * ''[[009#eof|EOF]]'' * ''[[009#loc|LOC]]'' * ''[[009#lof|LOF]]'' * ''[[009#fpos|FPOS]]'' Помните, однако, что имя устройства ''МЕМ:'' обязано присутствовать всякий раз при упоминании имени файла! Приведём несколько примеров записи операторов для работы с RAM диском: MERGE"MEM:файл" OPEN "MEM:файл" FOR INPUT AS#1 OPEN "MEM:файл" FOR OUTPUT AS#6 OPEN "MEM:файл" FOR APPEND AS#15 SAVE"MEM:файл" LOAD"MEM:файл" RUN"MEM:файл" {{anchor:e094-01}} __//Пример//__. \\ {{.examples:094-01.bas|}} \\ [[+tab|wmsxbpge>094-01.bas]] CALL MEMINI Ok 10 OPEN "MEM:GAMES" FOR OUTPUT AS#1 20 FOR X=1 TO 3 30 INPUT"Введите название игры";F$:PRINT #1,F$ 50 NEXT X:CLOSE #1 60 PRINT"∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗" 80 OPEN "MEM:GAMES" FOR INPUT AS#1 90 FOR X=1 TO 3 100 INPUT #1,F$:PRINT F$ 110 NEXT X 120 CLOSE #1:SAVE"MEM:GAMES" run Введите название игры? Футбол Введите название игры? Шашки Введите название игры? Хоккей ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ Футбол Шашки Хоккей Ok Команда ''SAVE'' всегда записывает программу в формате ASCII, после чего она "готова к употреблению" операторами ''MERGE'' и ''RUN''. Отметим, что на RAM диске может существовать один файл с //пустым// именем. Таким образом, синтаксически допустимы следующие конструкции: SAVE"MEM:" LOAD"MEM:" RUN"MEM:" MERGE"MEM:" OPEN"MEM:" {{anchor:fpos}} Функция FPOS(Номер файла) возвращает оставшийся объем RAM диска. Все остальные операторы и функции, перечисленные выше,используются аналогично соответствующим конструкциям,используемым в версии [[msx:disk_basic]]. {{anchor:n95}} ===== IX.5. Файлы на магнитной ленте ===== Вывод программных файлов и файлов данных из оперативной памяти на магнитную ленту и обратное считывание с ленты в память реализуется через устройство, называемое //магнитофоном//. Для идентификации файлам присваиваются //имена//, конструируемые из символов алфавита языка. Поподробнее о формате хранения я особенностях работы описано [[msx:data_recorder|здесь]]. Длина имени не может превосходить 6 символов (операторы ''SAVE'', ''CSAVE'') или 11 (оператор ''BSAVE''). Уникальность имён не обязательна. Работа с магнитофоном может быть организована в рамках любой версии языка [[msx:basic:]]. Для этих целей предусмотрены приведённые ниже команды и функции. {{anchor:motor}} Для управления мотором магнитофона есть специальная команда [[bibliography#b101|[101]]]: MOTOR Для включения мотора используется параметр ''ON'': MOTOR ON , для выключения ''OFF'': MOTOR OFF Команда без периметров переключает значение ''ON''/''OFF''. FIXME |< 100% 20% 80% >| |''[[009#save2|SAVE]]''|команда записи в формате ASCII программ из оперативной памяти на магнитную ленту| |''[[009#load2|LOAD]]''|команда чтения в оперативную память программ, записанных на магнитной ленте в формате ASCII| |''[[009#merge2|MERGE]]''|команда подгрузки в память программ, записанных на ленте в формате ASCII| |''[[009#run2|RUN]]''|команда загрузки в память программ, записанных на ленте в формате ASCII, с автоматическим запуском их на счёт| |''[[#CSAVE]]''|команда записи во внутреннем представлении программ (см. [[202|]]) из оперативной памяти на ленту| |''[[#CLOAD]]''|команда чтения в оперативную память (или верификации) программ, записанных на ленте во внутреннем представлении (см. [[202|]])| |''[[#BSAVE]]''|команда записи во внутреннем представлении программных файлов или файлов данных из конкретного участка оперативной памяти на ленту| |''[[#BLOAD]]''|команда считывания в определённую область оперативной памяти программных файлов и файлов данных, записанных на ленте во внутреннем представлении (см. [[202|]])| |''[[009#open|OPEN]]''|операторы и функции для работы с файлами данных последовательного доступа| |''[[009#close|CLOSE]]''|:::| |''MAXFILES=''|:::| |''[[009#eof|EOF]]''|:::| |''[[009#print1|PRINT #]]''|:::| |''[[009#print_using|PRINT #,USING]]''|:::| |''[[009#input|INPUT#]]''|:::| |''[[009#lineinput|LINE INPUT #]]''|:::| |''[[009#input1|INPUT$]]''|:::| Приступим к краткому описанию синтаксиса и семантики упомянутых выше средств организации файлов на магнитной ленте и работы с ними. ==== IX.5.1. Работа с программными файлами ==== FIXME В этом пункте описаны команды ''[[009#save2|SAVE]]'', ''[[009#load2|LOAD]]'', ''[[009#merge2|MERGE]]'', ''[[009#run2|RUN]]''. {{anchor:save2}} Команда SAVE α [,A] , где: * ''SAVE'' — служебное слово; * α — строковое выражение; записывает в формате ASCII на магнитную ленту программу из оперативной памяти. Имя программы формируется из первых 6 символов значения строкового выражения α. Оно должно начинаться префиксом ''%%"CAS:"%%'', который в этом случае рассматривается как //имя устройства// и не учитывается при подсчёте длины α, например: SAVE"CAS:СОСНА" , SAVE"CAS:анкета",A . Заметим, что имя программы может быть опущено. Например: SAVE"CAS:" {{anchor:load2}} Выполнение команды LOAD α [,R] , где: * ''LOAD'' — служебное слово; * α — строковое выражение, значение которого определяет имя файла; наличие параметра R приводит к автоматическому запуску загруженной программы на счёт, начинается с закрытия всех файлов и чистки оперативной памяти от программ и данных. Далее программа, записанная на ленте в формате ASCII под именем, равным значению строкового выражения α, считывается в память. Например: LOAD"CAS:труба" , LOAD"CAS:King",R . Поиск конкретной программы на ленте сопровождается индикацией сообщений обо всех "попавшихся под руку" при этом файлах с другими именами, записанных в формате ASCII. Приведём пример сообщения на экране дисплея при выполнении команды ''LOAD''(учтите, что: "to skip" — "перескочить", "to found" — "находить"): Skip:PRIM1 Skip: ◀── встретилась программа без имени Found:PRIM3 Found: ◀── найдена и загружается программа без имени Команда LOAD"CAS:" [,R] считывает в память первую встреченную на ленте программу в формате ASCII. {{anchor:run2}} RUN α Эта команда, если в ней указаны имя устройства и имя программы, загружает и запускает на выполнение программу, сохранённую в формате ASCII. Она похожа на команду ''LOAD'' (с параметром R), за тем исключением, что она загружает программы только в формате ASCII и закрывает все открытые файлы. В обоих случаях перед загрузкой программы автоматически выполняется команда ''NEW''. ''//Пример//''. \\ Команда RUN"CAS:PROG1" загружает и запускает программу с именем "PROG1", сохранённую на магнитной ленте командой SAVE"CAS:PROG1" {{anchor:merge2}} При выполнении команды MERGE α , где: * ''MERGE'' — служебное слово; * α — строковое выражение, значение которого определяет имя файла, закрываются файлы и организуется "чистка" оперативной памяти от данных. Затем, программа, записанная на ленте в формате ASCII под именем, равным значению строкового выражения α, "сливается" с программой β, находящейся в памяти. При этом, если в α и β совпадают некоторые номера строк,то сохраняются лишь соответствующие строки загружаемой программы α. Например: MERGE"CAS:Мама!" Выдача сообщений на экране при поиске программы α здесь такая же, как и в случае с командой ''LOAD''. Команда MERGE"CAS:" подгружает в память первую встреченную на ленте в формате ASCII программу. Обратите внимание на тот факт,что программы, вызываемые командой ''MERGE'', имеют более высокий приоритет, по сравнению с программами, находящимися в памяти компьютера. Поэтому если в объединяемых программах имеются строки с одинаковыми номерами, то строки программы в памяти компьютера будут заменены соответствующими строками "добавляемой" программы. {{anchor:csave}} * А. Команда (оператор) ''CSAVE'' "сохраняет"программу, записывая её на кассету магнитной ленты. Формат оператора: CSAVE β;[S] , где: * ''CSAVE'' ("Casette SAVE" — "запись на кассету") — служебное слово; * β — строковое выражение, значение которого определяет имя файла, в имени программы допускается использование любых символов, причём значащими в имени являются только первые шесть символов; * S — арифметическое выражение, целая часть значения которого равна 1 или 2 и определяет скорость записи данных (по умолчанию значение параметра S равнo 1): * 1 — 1200 бод (1200 бит/с) * 2 — 2400 бод (2400 бит/с) Скорость 2400 бод требует использования хорошего магнитофона и высококачественной ленты. Скорость работы по умолчанию может быть переопределена в операторе ''SCREEN'' (см.раздел [[05#n7|V.7.]]). Команда ''CSAVE'' "сохраняет" программу во //внутреннем// формате, т.е. в том виде, в каком она хранится в памяти компьютера (см. [[202|]]). //Примеры//: * α) команда CSAVE"PROG1" сохраняет файл, имя которого "PROG1", во внутреннем формате (см. [[202|]]) со скоростью 1200 бод (или со скоростью, определённой оператором ''SCREEN''); * β) команда CSAVE"PROG2",2 сохраняет файл с именем "PROG2" на кассетной ленте во внутреннем формате (см. [[202|]]) со скоростью 2400 бод. * {{anchor:cload}}B. Команда CLOAD β , где: * ''CLOAD'' ("Cassette LOAD" — "загрузка с кассеты") — служебное слово; * β — строковое выражение, значение которого определяет имя файла, позволяет загружать программу, сохранённую на кассетной ленте во внутреннем формате (с помощью команды ''CSAVE''). Загрузка выполняется на той же скорости, на которой программа была сохранена. Таким образом, вам не нужно повторно указывать скорость. Если имя программы не указано в операторе, то будет загружена первая же программа, сохранённая во внутреннем формате (см. [[202|]]). Если Вы указываете имя программы,то следите за правильностью ввода имени (т.е., например, если Вы использовали прописные буквы при написании имени, Вы должны ввести имя программы также прописными буквами). Заметим, что оператор ''CLOAD'' автоматически выполняет команду ''NEW'' перед началом загрузки в память найденной программы. * {{anchor:cload1}} С. Оператор ''CLOAD?'' проверяет правильность сохранения программы на кассетной ленте. После сохранения программы перемотайте ленту назад и введите команду CLOAD? β , где: * ''CLOAD?'' ("Casette LOAD verify" — "загрузка с ленты") — служебное слово; * β — строковое выражение, значение которого определяет имя файла. Записанная программа, имя которой указано в операторе, сравнивается байт за байтом с текстом программы в памяти компьютера. При обнаружении несовпадения эта процедура прекращается и на экране появляется сообщение об ошибке: "Verify error" (//"Ошибка верификации"//). Имя программы может быть опущено. В этом случае с содержимым памяти будет сравниваться первая введённая с ленты программа. Если имя программы не совпадает с именем, указанным в операторе, поиск программы с указанным именем будет продолжен. На экране дисплея появится следующее сообщение: Skip:имя программы В нем указано имя найденной "по пути" программы или файла данных. * D. По команде {{anchor:bsave}} BSAVE α,β1,β2[,β3] , где: * ''BSAVE'' ("Binary SAVE") — служебное слово; * α — строковое выражение; * β1,β2,β3 — арифметические выражения, значения которых задают адреса в RAM, содержимое оперативной памяти от β1 и до β2 записывается во внутреннем представлении (см. [[202|]]) на ленту под именем, равным значению строкового выражения α. Значение выражения β3 определяет адрес, с которого программа при загрузке её в память будет запускаться на счёт (по умолчанию значение β3 равно значению β1). Если вывод осуществляется не на дисковод А, то следует указать имя устройства. Затем укажите: * имя файла, * начальный адрес сохраняемых данных, * конечный адрес сохраняемых данных и, возможно, * адрес выполнения; если последний пропущен, то адрес, отмечающий начало данных, будет автоматически рассматриваться как адрес выполнения при загрузке этих данных (эта часть информации полезна только в том случае, если сохраняются подпрограммы на машинном языке). __//Примеры//__. * BSAVE "CAS:ГОСТ",&HF000, &HF0EE * BSAVE "CAS:" A,B,C Команда ''BSAVE'' позволяет сохранить часть оперативной памяти на ленте или дискете. Это может быть подпрограмма на [[msx:basic:]], данные, подпрограммы ROM, рабочая область. Оператором ''BSAVE'' может быть сохранена часть памяти между ячейками с адресами &H0 и &HFFFF FIXME {{anchor:bsave_v}} [[bibliography#b101|[101]]] На компьютерах [[msx:msx_2]] возможна и другая форма записи оператора ''BSAVE'': BSAVE"CAS: имя файла",β1,β2,S . Этот оператор сохраняет на кассетной ленте содержимое видеопамяти. * {{anchor:bload}}E. По команде BLOAD α,[,R][,β] , где: * ''BLOAD'' ("Binary LOAD") — служебное слово; * α — строковое выражение; * R — параметр; * β — арифметическое выражение;значение параметра β должно быть целым, оно определяет величину смещения адресов β1, β2 и β3 загрузки и запуска (по умолчанию β=0), в оперативную память загружается файл, записанный на ленте во внутреннем представлении (см. [[202|]]) под именем, равным значению выражения α. При наличии параметра R прочитанная программа автоматически запускается на счёт. //Примеры//. - BLOAD "CAS:DD" - BLOAD "CAS:LEN", &H1500 - BLOAD "CAS:TEST", R - BLOAD "CAS:",R - {{anchor:e0951-05}} {{.examples:0951-05.bas|}} \\ [[+tab|wmsxbpge>0951-05.bas]] FIXME 5 'Инициализация компьютера. 10 CALL NETEND 'Для компьютеров серии MSX 2 20 BSAVE"CAS:initio",0,3 30 BLOAD"CAS:initio",R,&HA000 В последнем примере подпрограмма ROM, расположенная между адресами &h0 и &h3, загружается в RAM по адресу &HA000 и запускается на выполнение. Команда ''BLOAD'' позволяет загрузить данные, сохранённые командой ''BSAVE''. Должно быть указано имя устройства, если это не дисковод А, и имя файла. Может присутствовать параметр R, если данные относятся к программе на машинном языке. В этом случае программа запустится после загрузки. Данные загружаются на то место, которое они занимали перед сохранением, если не указан адрес смещения. В этом случае данное число добавляется к начальному, конечному и адресу смещения, заданным в команде ''BSAVE''. FIXME {{anchor:bload_v}} [[bibliography#101|[101]]] На компьютерах [[msx:msx_2]] возможна и другая форма записи оператора ''BLOAD'': BLOAD"CAS: имя файла",S Содержимое файла будет скопировано в видеопамять. Обратите внимание, что ''BLOAD'' может использоваться в программе, не вызывая выполнения команды ''NEW'' или возврата в командный режим. Этот оператор может использоваться также для загрузки частей программы на [[msx:basic:]]. {{anchor:e0951-11}} __//Пример 1//__. Приведём программу, которая позволяет указать начальный и конечный адреса загрузки двоичного файла. \\ FIXME {{.examples:0951-11.bas|}} \\ [[+tab|wmsxbpge>0951-11.bas]] 1 INPUT"Имя файла";A$ 10 OPEN A$ FOR INPUT AS#1 20 FOR I=1 TO 7 30 I$(I)=INPUT$(1,#1) 40 PRINT ASC(I$(I)),HEX$(ASC(I$(I))) 50 NEXT 60 CLOSE 65 IF I$(1)<>"Ч" THEN PRINT"Это не BLO-файл! ":END 66 PRINT"Вы хотите вывести адреса на принтер (д/н)?" 67 Y$=INKEY$:IF Y$="" THEN 67 68 IF Y$="д" OR Y$="Д" THEN LPRINT A$ 69 A1=256*ASC(I$(3))+ASC(I$(2)) 70 PRINT "Начальный адрес:";HEX$(A1);" или";A1 71 IF Y$="д"OR Y$="Д" THEN LPRINT"Начальный адрес:";HEX$(A1);" или";A1 79 A2=256*ASC(I$(5))+ASC(I$(4)) 80 PRINT "Конечный адрес:";HEX$(A2);" или";A2 81 IF Y$="д" OR Y$="Д" THEN LPRINT"Конечный адрес:";HEX$(A2);" или";A2 89 A3=256*ASC(I$(7))+ASC(I$(6)) 90 PRINT "Адрес запуска:";HEX$(A3);" или";A3 91 IF Y$="д" OR Y$="Д" THEN LPRINT"Адрес запуска:";HEX$(A3);" или";A3 //Замечание//. Команды ''BSAVE'' и ''BLOAD'' можно применять и для работы с произвольными дисковыми файлами (устройства ''A:'' и ''B:''). __//Пример 2//__. Запись компьютерных игр с дискеты на магнитную ленту. - Загрузите программу с дискеты в оперативную память командой BLOAD "имя файла" - Включите Ваш магнитофон на запись, затем выполните команду BSAVE "CAS:имя файла",α,β,γ где: * α — //шестнадцатеричный// начальный адрес; * β — //шестнадцатеричный// конечный адрес; * γ — //шестнадцатеричный// адрес загрузки. Значения α,β,γ Вы можете найти с помощью программы из примера 1. __//Пример 3//__. Загрузка компьютерных игр с магнитной ленты в оперативную память. - Включите магнитофон - Выполните команду BLOAD "CAS: Имя файла",R - На экране появится надпись: Found: Имя файла (без расширения) - …И "игрушка" запустится! ==== IX.5.2. Работа с файлами данных ==== Команда ''OPEN'' для устройства ''CAS:'' имеет следующий вид: ⎧ INPUT OPEN β FOR ⎨ AS #n ⎩ OUTPUT , Здесь β должно начинаться с символов '' %% "CAS:" %%'' и, кроме того, отсутствует возможность, предоставляемая параметром APPEND для "наращивания" файлов. Все остальное полностью аналогично работе с дисковыми файлами (устройства ''A:'', ''B:'' и ''MEM:''). {{anchor:e0952-01}} __//Пример//__. \\ Строки 10÷30 создают файл данных на магнитной ленте. Для его считывания в память требуется запустить этот фрагмент со строки 50. \\ {{.examples:0952-01.bas|}} \\ [[+tab|wmsxbpge>0952-01.bas]] FIXME 10 OPEN"CAS:хи-хи" FOR OUTPUT AS #1 20 FOR K=1 TO 500:PRINT #1,K;:NEXT 30 CLOSE #1 40 STOP 50 CLEAR 1000 60 OPEN"CAS:хи-хи" FOR INPUT AS #1 70 LINE INPUT #1,M$:PRINT M$; 80 IF NOT EOF(1) THEN 70 90 END ===== IX.6. Дополнение ===== Три очень //полезных// программы. {{anchor:e096-01}} 1. Программа, осуществляющая посекторное копирование диска на кассету. \\ {{.examples:096-01.bas|}} \\ [[+tab|wmsxbpge>096-01.bas]] FIXME 6 CLS:PRINT:PRINT"<<Посекторное копирование диска на кассету>>":PRINT:PRINT 11 DEFINT A-Z:GOSUB 51:I=&H9000:DEFUSR=I:J=&HA000:DEFUSR1=J:PRINT"Сколько минут протягивается одна сторона кассеты ??":INPUT CT:PRINT:PRINT"С какого по какой сектор копировать S1, S2 (0-1500)??":INPUT S1,S2 16 READ D$:IF D$<>"#" THEN POKE I,VAL("&h"+D$):I=I+1:GOTO 16 21 DATA 2A,51,F3,11,00,00,01,00,02,CD,5C,00,C9,# 22 READ D$:IF D$<>"#" THEN POKE J,VAL("&h"+D$):J=J+1:GOTO 22 23 DATA 2A,51,F3,11,00,B0,01,00,02,ED,B0,C9,# 31 FOR S=S1 TO S2:D$=DSKI$(1,S):CLS:U=USR(0):LOCATE 0,17:PRINT "Сектор N";S:I=USR1(0):BSAVE"CAS:С"+STR$(S),&HB000,&HB1FF:GOSUB46:IF T>CT-5 THEN GOSUB 56 36 NEXT:END 46 GET TIME T$:KEY 2,T$:C1$=LEFT$(T$,2):C1=VAL(C1$)-C:M1$=MID$(T$,4,2):M1=VAL(M1$)-M:T=C1*60+M1:RETURN 51 GET TIME T$:KEY1,T$:C$=LEFT$(T$,2):C=VAL(C$):M$=MID$(T$,4,2):M=VAL(M$):RETURN 56 CLS:LOCATE 10,10:PRINT "Проверь ленту":LOCATE 10,12:PRINT"Кончилась ??? (D/N)":SET BEEP 4,4 61 BEEP:O$=INKEY$:IF O$="" THEN 61 ELSE ON INSTR("@@@DdдДNnнН",O$)\4 GOTO 66,76:GOTO 61 66 PRINT "Вставил новую ? (D)":SET BEEP 3,4 71 BEEP:O$=INKEY$:IF O$="" THEN 71 ELSE IF INSTR("DdдД",O$)THEN GOSUB 51:RETURN ELSE 71 76 RETURN {{anchor:e096-02}} 2. Программа, осуществляющая посекторное восстановление диска с кассеты. \\ {{.examples:096-02.bas|}} \\ [[+tab|wmsxbpge>096-02.bas]] FIXME 6 CLS:PRINT:PRINT"<<Посекторное восстановление диска с кассеты>>":PRINT:PRINT 11 DEFINT A-Z:GOSUB 51:I=&H9000:DEFUSR=I:J=&HA000:DEFUSR1=J:PRINT"Сколько минут протягивается одна сторона кассеты ??":INPUT CT:PRINT:PRINT"С какого по какой сектор копировать S1, S2 (0-1500) ??":INPUT S1,S2 16 READ D$:IF D$<>"#" THEN POKE I,VAL("&h"+D$):I=I+1:GOTO 16 21 DATA 21,00,B0,11,00,00,01,00,02,CD,5C,00,C9,# 22 READ D$:IF D$<>"#" THEN POKE J,VAL("&h"+D$):J=J+1:GOTO 22 23 DATA 01,00,02,2A,51,F3,54,5D,21,00,B0,ED,B0,C9,# 31 FOR S=S1 TO S2:BLOAD"CAS:С"+STR$(S):CLS:U=USR(0):LOCATE 0,17:PRINT"Сектор N";S:I=USR1(0):DSKO$ 1,S:GOSUB 46:IF T>CT-5 THEN GOSUB 56 36 NEXT:END 46 GET TIME T$:KEY 2,T$:C1$=LEFT$(T$,2):C1=VAL(C1$)-C:M1$=MID$(T$,4,2):M1=VAL(M1$)-M:T=C1*60+M1:RETURN 51 GET TIME T$:KEY 1,T$:C$=LEFT$(T$,2):C=VAL(C$):M$=MID$(T$,4,2):M=VAL(M$):RETURN 56 CLS:LOCATE 10,10:PRINT "Проверь ленту":LOCATE 10,12:PRINT "Кончилась ??? (D/N)":SET BEEP 4,4 61 BEEP:O$=INKEY$:IF O$="" THEN 61 ELSE ON INSTR("@@@DdдДNnнН",O$)\4 GOTO 66,76:GOTO 61 66 PRINT "Вставил новую ?(D)":SET BEEP 3,4 71 BEEP:O$=INKEY$:IF O$="" THEN 71 ELSE IF INSTR("DdдД",O$)THEN GOSUB 51:RETURN ELSE 71 76 RETURN {{anchor:e096-03}} 3. Программа, позволяющая определить тип файла на кассете. \\ {{.examples:096-03.bas|}} \\ [[+tab|wmsxbpge>096-03.bas]] //Внимание//! При наборе программы //строго// соблюдайте пробелы между символами и нумерацию строк. FIXME 1 WIDTH40:PRINT"<<< FORMAT FILES ON CASSETTE >>>":PRINT:KEYOFF:PRINT"<<< BY LEO BOYARSKY (c) 1988 >>>":POKE&H80CA,143' 2 CLEAR1000:MAXFILES=1:ONSTOPGOSUB15:STOPON:ONERRORGOTO14:RESTORE4:A=VARPTR(#1):NEW' 3 DEFFNA$(I)=RIGHT$("000"+HEX$(PEEK(I)+256*PEEK(I+1)),4) 4 FORI=0TO8:READX:POKEA+I,X:NEXT:DATA1,0,0,0,255,0,0,0,0' 5 DATA&HDB,&HC3,&H32,&H58,&HD3,&HC3,&H74,&H42 6 PRINT:X$=INPUT$(255,1) 7 W$="":FORI=A+9 TOA+18:W=PEEK(I):W$=W$+CHR$(W):NEXT 8 N$="":FORI=A+19TOA+24:N=PEEK(I):N$=N$+CHR$(N):NEXT 9 IFW$="сссссссссс"THENW$="BASIC (cload)":GOSUB11ELSEIFW$="ЙЙЙЙЙЙЙЙЙЙ"THENW$="BASIC ( load)":GOSUB11ELSEIFW$="пппппппппп"THENW$="OBJEKT (bload)":GOSUB11:I=A+25:GOSUB12 10 PRINT:PRINT"<<< Checking next file >>>":RUN2 11 S$=" The "+N$+" is "+W$+" file.":PRINTS$:RETURN 12 SA$=FNA$(I):IFNOT(("8"<=SA$)AND(SA$<="F380"))THEN13ELSEEA$=FNA$(I+2):IFNOT(("8"<=EA$)AND(EA$<="F380"))THEN13ELSERA$=FNA$(I+4):IFNOT(("8"<=RA$)AND(RA$<="F380"))THEN13ELSES$=S$+CHR$(13)+"Start:&h"+SA$+"; End: &h"+EA$+"; Run: &h"+RA$:PRINTS$:RETURN 13 I=I+1:IFI>A+255THENPRINT:PRINT"Don't check address !":RETURNELSE12 14 RESUMENEXT 15 KEYON:POKE&H80CA,58' 16 END {{anchor:examples9}} ====== Диск с примерами ====== {{.examples:examples09.dsk|Загрузить образ диска}} [[+tab|wmsxbpged>examples09.dsk|Открыть диск в WebMSX]] ---- [<>] {{tag>MSX msxbdpl}}