[<>]
~~TOC wide 1-6 ~~
====== I. Дискеты и их характеристики ======
┌────────┬────────┬────────┬────────┬────────┐
│0 сектор│1 сектор│2 сектор│3 сектор│4 сектор│
└──▲─────┴────────┴────────┴────────┴────────┘
│ │◀——————FAT —————▶│◀—— Копия FAT ——▶│
│
Загрузочный сектор ("Boot sector")
┌────────┬────────┬────────┬────────┬────────┬────────┬────────┐
│5 сектор│6 сектор│7 сектор│8 сектор│9 сектор│A сектор│B сектор│
└────────┴────────┴────────┴────────┴────────┴────────┴────────┘
│◀—————————————————— Каталог ("Directory") ———————————————————▶│
┌────────┬────────┬────────┬────────┬─────────┬─────────┬──────┐
│C сектор│D сектор│E сектор│F сектор│10 сектор│11 сектор│ ... │
├────────┴────────┼────────┴────────┼─────────┴─────────┼──────┤
│ 2-й кластер │ 3-й кластер │ 4-й кластер │ ... │
└────────┴────────┴────────┴────────┴─────────┴─────────┴──────┘
│◀——————————————— Область данных ("Data Area") ———————————————▶│
* b) //двухстороннего диска//:
┌────────┬────────┬────────┬────────┬────────┬────────┬────────┐
│0 сектор│1 сектор│2 сектор│3 сектор│4 сектор│5 сектор│6 сектор│
└──▲─────┴────────┴────────┴────────┴────────┴────────┴────────┘
│ │◀————————— FAT ——————————▶│◀—————— Копия FAT ———————▶│
│
Загрузочный сектор ("Boot sector")
┌────────┬────────┬────────┬────────┬────────┬────────┬────────┐
│7 сектор│8 сектор│9 сектор│A сектор│B сектор│C сектор│D сектор│
└────────┴────────┴────────┴────────┴────────┴────────┴────────┘
│◀——————————————————— Каталог ("Directory") ——————————————————▶│
┌────────┬────────┬─────────┬─────────┬─────────┬─────────┬────┐
│E сектор│F сектор│10 сектор│11 сектор│12 сектор│13 сектор│... │
├────────┴────────┼─────────┴─────────┼─────────┴─────────┼────┤
│ 2-й кластер │ 3-й кластер │ 4-й кластер │... │
└────────┴────────┴─────────┴─────────┴─────────┴─────────┴────┘
│◀——————————————— Область данных ("Data Area") ———————————————▶│
┌─────────────┐
00h │E9h или 0EBh │
├─────────────┤
01h — 09h│ —Х—Х—Х—Х—Х— │ ◀——— Служебная информация
├──────┬──────┤
0Bh,0Ch │ ▧▧▧▧ │ ▧▧▧▧ │ ◀——— Количество байтов в секторе
├──────┴──────┤
0Dh │ │ ◀——— Количество секторов в кластере
├──────┬──────┤
0Eh,0Fh │ ▧▧▧▧ │ ▧▧▧▧ │ ◀——— Количество неиспользованных секторов
├──────┴──────┤
10h │ │ ◀——— Количество Таблиц Расположения Файлов
├──────┬──────┤
11h,12h │ ▧▧▧▧ │ ▧▧▧▧ │ ◀——— Максимальное количество файлов
├──────┼──────┤
13h,14h │ ▧▧▧▧ │ ▧▧▧▧ │ ◀——— Количество секторов на дискете
├──────┴──────┤
15h │ │ ◀——— Идентификатор носителя
├──────┬──────┤
16h,17h │ ▧▧▧▧ │ ▧▧▧▧ │ ◀——— Количество секторов в FAT
├──────┼──────┤
18h,19h │ ▧▧▧▧ │ ▧▧▧▧ │ ◀——— Количество секторов в треке
├──────┼──────┤
1Ah,1Bh │ ▧▧▧▧ │ ▧▧▧▧ │ ◀——— Количество сторон диска
├──────┼──────┤
1Ch,1Dh │ ▧▧▧▧ │ ▧▧▧▧ │ ◀——— Количество "спрятанных" секторов
├──────┴──────┤ (для MS-DOS)
1Eh │ │
├─────────────┤ ⎫
1Fh — 22h│ ED 53 59 C0 │ ◀——— LD (C059),DE⎪
├─────────────┤ ⎪
... │ ... │ ... │
├─────────────┤ │
A9h │ 0A │ ◀——— LD A,(BC) ⎬ Программа-загрузчик
├─────────────┤ │ системного Файла
AAh │ 00 │ ◀——— NOP │
├─────────────┤ │
ABh │ 00 │ ◀——— NOP │
├─────────────┤ ⎭
ACh — B6h│ MSXDOS SYS │ ◀——— Имя системного файла
├─────────────┤ (по умолчанию MSXDOS.SYS)
... │ Не │
... │ используется│
├─────────────┤
1FFh │ 00 │
└─────────────┘
┌─────┬────────────────────────────────────────────────────┬──────────┐
│Адрес│ Программа на Ассемблере с комментариями │ Коды │
├─────┼────────────────────────────────────────────────────┼──────────┤
│0D0h:│ LD DE,D000h ; Установка нового │ 11 00 D0 │
│ │ LD C,1Ah ; адреса передачи │ 0E 1A │
│ │ CALL F37Dh ; boot–сектора. │ CD 7D F3 │
│ │ LD HL,100h ; Загрузка одного сектора │ 21 00 01 │
│ │ LD DE,0 ; (с номером 0) с диска, │ 11 00 00 │
│ │ LD C,2Fh ; находящегося в дисководе "А". │ 0E 2F │
│ │ CALL F37Dh ; │ CD 7D F3 │
│ │ JP D100h ; Переход на адрес Вашей программы. │ C3 00 D1 │
│ │ ... │ │
│100h:│ ; Здесь располагается Ваша программа.│ │
│ │ ... │ │
│1FDh:│ JP 100h ; Переход на адрес прогр. MSXDOS.SYS.│ C3 00 01 │
└─────┴────────────────────────────────────────────────────┴──────────┘
//Обратите внимание//: //функции// BDOS вызываются командой ''CALL F37Dh'', т.к. //программа загрузки// работает в рабочей области слота "BASIC" //(слот 0)//.
__Примечание.__ Как только Вы начинаете работать с дискетой в системную область слота 3-2 помещается информация о дискете, которая //может изменяться// в процессе работы с дискетой.
┌─────────────┐
00h │ 00 │ ◀——— Номер дисковода
├─────────────┤
01h │ F9 │ ◀——— Идентификатор носителя
├──────┬──────┤
02h,03h│ 00 │ 02 │ ◀——— Размер сектора
├──────┴──────┤
04h │ 0F │ ◀——— Маска каталога = Размер сектора/32-1
├─────────────┤
05h │ 04 │ ◀——— Сдвиг каталога = Количество единичных
├─────────────┤ битов в Маске каталога
06h │ 01 │ ◀——— Маска кластера = (Сектор/Кластер) - 1
├─────────────┤
07h │ 02 │ ◀——— Сдвиг кластера = 1 + Количество единичных
├──────┬──────┤ битов в Маске кластера
08h,09h│ 01 │ 00 │ ◀——— Первый сектор FAT
├──────┴──────┤
0Ah │ 02 │ ◀——— Количество FAT
├─────────────┤
0Bh │ 70 │ ◀——— Количество файлов (70h=112)
├──────┬──────┤
0Ch,0Dh│ 0E │ 00 │ ◀——— Первый сектор Области данных (Data Area)
├──────┼──────┤
0Eh,0Fh│ CA │ 02 │ ◀——— Количество кластеров + 1
├──────┴──────┤
10h │ 03 │ ◀——— Количество секторов в FAT
├──────┬──────┤
11h,12h│ 07 │ 00 │ ◀——— Первый сектор каталога
├──────┼──────┤
13h,14h│ 95 │ E5 │ ◀——— Адрес FAT в памяти
└──────┴──────┘
* β) //размещение// DPB:
┌─────────────────┬─────────────────────────────────┐
│Адреса в рабочей │ Назначение (или содержимое) │
│области слота 3-2│ │
├─────────────────┼─────────────────────────────────┤
│ F195 ÷ F1A9 │ DPB дисковода "A" │
│ F1AA ÷ F1BE │ DPB дисковода "B" │
│ │ │
│ F1BF │ 0 │
│ F1C0 │ 0 │
│ F1C1 │ Текущий дисковод (0 соотв. "А") │
│ F1C2 │ Текущий трек (дисковод A) │
│ F1C3 │ Текущий трек (дисковод B) │
│ F1C4 │ Протокол текущего дисковода │
│ F1C5 │ Трек (разметка) │
│ F1C6 │ Тип носителя (форматирование) │
│ F1C7 │ Число дисководов в системе │
│ F1C8 │ 0 │
│ │ │
│ F161 ÷ F175 │ DPB дисковода "C" │
│ F176 ÷ F18A │ DPB дисковода "D" │
│ │ │
│ F18B ÷ F194 │ Аналогично байтам F1BF ÷ F1C8 │
│ │ │
├─────────────────┼─────────────────────────────────┤
│ │ │
│ E595 ÷ EB94 │ Копия Таблицы размещения файлов │
│ │ │
│ EB95 ÷ ED94 │ Копия сектора каталога, │
│ │ содержащего последний │
│ │ упомянутый Вами файл │
│ │ │
└─────────────────┴─────────────────────────────────┘
{{anchor:n121e}}
=== Как спасти только что уничтоженный текстовый файл ===
dri[V]e , [B] ;
[W]rite , <номер пустого кластера на диске в дисководе "В">;
dri[V]e , [A] ;
[R]ead , <номер следующего кластера на диске в дисководе "А">.
Это очень неприятно — запоминать (или записывать) номера кластеров, с которыми работаешь, но если уж убиваешь файл, думай о последствиях!
1024∙(Nlast + 1 - Nfirst)
Число_кластеров = 1 + Объем_файла div #400
и переведите полученный результат в десятичную систему. Номер первого кластера и число кластеров записать или запомнить.
- Восстановить имя файла, вписав на место знака "*" первый символ имени (или любой другой, кроме символа "Е" русского алфавита) при помощи команд: ''[CR], <нужный символ>, [ESC]; [W]rite''.
* Второй этап.
┌────────┬────────┬────────┬────────┬────────┬────────┬────────┐
│0 сектор│1 сектор│2 сектор│3 сектор│4 сектор│5 сектор│6 сектор│
└──▲─────┴────────┴────────┴────────┴────────┴────────┴────────┘
│ │◀————————— FAT ——————————▶│◀—————— Копия FAT ———————▶│
│
Загрузочный сектор ("Boot sector")
Если же диск отформатирован как //односторонний// ("Single"), то FAT занимает уже не 3, а 2 сектора, и размещается в секторах 1÷2, а копия — в секторах 3÷4.
┌────────┬────────┬────────┬────────┬────────┐
│0 сектор│1 сектор│2 сектор│3 сектор│4 сектор│
└──▲─────┴────────┴────────┴────────┴────────┘
│ │◀————— FAT —————▶│◀—— Копия FAT ——▶│
│
Загрузочный сектор ("Boot sector")
Предполагается, что копии Таблицы Размещения Файлов должны быть идентичными. Хранение двух экземпляров Таблицы Размещения Файлов представляет собой простую предосторожность, связанную с большой важностью информации, содержащейся в таблице. Восстановление поврежденной FAT представляет собой непростую задачу.
Для Таблицы Размещения Файлов выделено 4 (или 6) секторов не столько для того, чтобы хранить две копии, сколько для обеспечения возможности увеличения этой Таблицы в будущем.
//Основной принцип// организации Таблицы Размещения Файлов заключается в создании таблицы, каждый элемент которой соответствует одному кластеру.
//Элементы таблицы содержат признаки занятости кластера//.
\\ //Доступные// (свободные) элементы таблицы содержат //нулевые// значения.
\\ Участки пространства на дискете, принадлежащие одному файлу, связаны в //цепочку//. Опишем организацию этой цепочки.
Во-первых, определенный элемент //Справочника// файла (см. ниже [[#n123|раздел I.2.3]]) содержит номер элемента в Таблице Размещения Файла, который соответствует первому из кластеров, выделенных для файла.
Во-вторых, каждый элемент Таблицы Размещения Файлов содержит номер //следующего// кластера файла и так далее, пока не будет достигнут последний кластер файла.
В-третьих, в последнем элементе Таблицы Размещения Файлов для данного файла находится //признак конца файла//.
┌─────────┬─────────┬─────────┬─────────┬─────┬─────────────┐
│ 0-й байт│ 1-й байт│ 2-й байт│ 3-й байт│ ... │ 1535-й байт │
│ FAT │ FAT │ FAT │ FAT │ │ FAT │
└─────────┴─────────┴─────────┴─────────┴─────┴─────────────┘
│◀———————————————————————————▶│
Информация о формате дискеты
Схема хранения чисел в виде полуторабайтных кодов выглядит довольно странно для программиста, хотя использование этого факта на машинном языке реализуется очень просто.
Последовательные элементы Таблицы Размещения Файлов разбиваются на пары, объединяющие два полуторабайтовых значения в последовательность из трех байтов для каждой пары.
Для получения значения, хранящегося в элементе Таблицы Размещения Файлов с номером X, нужно выполнить следующие действия:
- 1) умножить X на 1.5 (для этого выполняется умножение на 3 с последующим делением на 2), прибавить 3 и найти целую часть полученного значения:M := [X×1.5+3]
- 2) байты с адресами M и M+1 можно теперь загрузить в шестнадцатибитный регистр микропроцессора (кто не знает ассемблера микропроцессора Z80 — не бойтесь: это не больно!). Теперь в регистре находится четыре шестнадцатеричных цифры, а необходимы только //три// из них.
Если номер элемента Таблицы Размещения Файлов нечетный, то нужно отбросить //последнюю// цифру, а если он четный — то //первую//.
Старший бит ──╮ ╭── Младший бит
(номер 7) ▼ ▼ (номер 0)
┌────────────────────────────────┐
3–й байт FAT │ 07 06 05 04 03 02 01 00 │
├────────────────┐ │◀——— 0–й элемент FAT
4–й байт FAT │ 03 02 01 00 │11 10 09 08 │
│ └───────────────┤
5–й байт FAT │ 11 10 09 08 07 06 05 04 │◀——— 1–й элемент FAT
├────────────────────────────────┤
6–й байт FAT │ 07 06 05 04 03 02 01 00 │
├────────────────┐ │◀——— 2–й элемент FAT
7–й байт FAT │ │11 10 09 08 │
│ └───────────────┤
... │ ... │ ...
┌────────────────┐ │
1534–й байт FAT │ 03 02 01 00 │ │
│ └───────────────┐
1535–й байт FAT │ 11 10 09 08 07 06 05 04 │◀— 1021–й элемент FAT
└────────────────────────────────┘
Элементы FAT с содержимым 2CBh÷FFFh обозначают особые типы //зарезервированных// кластеров, например, EEEh в [[msx:dos:|]] используется для выделения кластеров с дефектными секторами. Дело в том, что на поверхности дискеты могут встречаться участки с дефектами магнитного покрытия, которые нельзя эффективно использовать для хранения данных.
В организации Таблицы Размещения Файлов могут возникать определенные дефекты. Два наиболее заметных дефекта — это //"беспризорные" кластеры// и //перекрещивающиеся файлы//.
Если элемент Таблицы содержит значение, указывающее, что элемент используется (значение не равно нулю) и, то же время, этот элемент не входит ни в одну из цепочек определения размещения файлов, то такой элемент Таблицы Размещения Файлов становится как бы //"беспризорным"//.
"Беспризорные" кластеры чаще всего возникают, когда программы начинают создавать файл (так что для него выделяются кластеры), но не закрывают его, вследствие чего не завершается создание элемента Справочника для данного файла.
Во втором случае, может случиться так, что две (или более) различные цепочки, определяющие размещение файлов, приводят к одному и тому же кластеру. Такие файлы называются //перекрещивающимися//.
Если "беспризорные" кластеры встречаются достаточно часто, то перекрещивающиеся файлы возникают очень редко. Если такая ситуация все же Вам встретится, нужно скопировать каждый из файлов на другую дискету для последующего восстановления (если оно потребуется). После этого копии всех файлов будут содержать информацию из общих секторов, хотя она может принадлежать только одному из них.
При работе [[msx:dos:|]] в памяти хранится копия Таблицы Размещения Файлов для каждого используемого дисковода (см. [[#n121|раздел I.2.1]]). Когда в Таблице производится какое-либо изменение, оно записывается в обе копии на дискете. При новом обращении к дискете [[msx:dos:|]] считывает Таблицу Размещения Файлов, чтобы установить формат дискеты.
{{anchor:n122e}}
┌────────┬────────┬────────┬────────┬────────┬────────┬────────┐
│5 сектор│6 сектор│7 сектор│8 сектор│9 сектор│A сектор│B сектор│
└────────┴────────┴────────┴────────┴────────┴────────┴────────┘
│◀————————————————— Справочник ("Directory") —————————————————▶│
и для //двухсторонней// дискеты:
┌────────┬────────┬────────┬────────┬────────┬────────┬────────┐
│7 сектор│8 сектор│9 сектор│A сектор│B сектор│C сектор│D сектор│
└────────┴────────┴────────┴────────┴────────┴────────┴────────┘
│◀————————————————— Справочник ("Directory") —————————————————▶│
Каждый элемент Справочника имеет длину 32 байта. Следовательно, в 512-байтном секторе помещается ровно 16 элементов Справочника. На дискете выделено 7 секторов для Справочника, что позволяет хранить 112 элементов (7×512/32 = 112).
Каждый элемент Справочника состоит из восьми полей следующего назначения:
Первое поле
┌────────────┐⎫
0–й байт│ ▧▧▧▧▧▧▧▧▧▧ ││
├────────────┤│
1–й байт│ ▧▧▧▧▧▧▧▧▧▧ ││ Имя файла (8 символов)
├────────────┤⎬ ◀—— (если некоторый символ отсутствует,то он
... │ ... ││ заменяется кодом 20h)
┌────────────┐│
7–й байт│ ▧▧▧▧▧▧▧▧▧▧ ││
└────────────┘⎭
Второе поле
┌────────────┐⎫
8–й байт│ ▨▨▨▨▨▨▨▨▨▨ ││
├────────────┤│ Расширение имени файла
9–й байт│ ▨▨▨▨▨▨▨▨▨▨ │⎬ ◀—— (если некоторый символ отсутствует, то он
├────────────┤│ заменяется кодом 20h)
10–й байт│ ▨▨▨▨▨▨▨▨▨▨ ││
└────────────┘⎭
Третье поле
┌────────────┐
11–й байт│ │ ◀—— Байт атрибутов файла
└────────────┘
Четвертое поле
┌────────────┐⎫
12–й байт│ :::::::::: ││
├────────────┤│
13–й байт│ :::::::::: ││
├────────────┤⎬ ◀—— Зарезервированное поле
... │ ... ││
┌────────────┐│
21–й байт│ :::::::::: ││
└────────────┘⎭
Пятое поле
┌────────────┐⎫
22–й байт│ ░░░░░░░░░░ ││
├────────────┤⎬ ◀—— Время создания файла
23–й байт│ ░░░░░░░░░░ ││
└────────────┘⎭
Шестое поле
┌────────────┐⎫
24–й байт│ ▧▧▧▧▧▧▧▧▧▧ ││
├────────────┤⎬ ◀—— Дата создания файла
25–й байт│ ▧▧▧▧▧▧▧▧▧▧ ││
└────────────┘⎭
Седьмое поле
┌────────────┐⎫
26–й байт│ ▨▨▨▨▨▨▨▨▨▨ ││ Ссылка на первый кластер, в котором
├────────────┤⎬ ◀—— находится файл (в 26–ом байте — младший
27–й байт│ ▨▨▨▨▨▨▨▨▨▨ ││ байт адреса, в 27–ом байте — старший байт)
└────────────┘⎭
Восьмое поле
┌────────────┐⎫
28–й байт│ ********** ││
├────────────┤│
29–й байт│ ********** ││
├────────────┤⎬ ◀——— Размер файла (в байтах)
30–й байт│ ********** ││
├────────────┤│
31–й байт│ ********** ││◀—— Старший байт размера файла
└────────────┘⎭
7 6 5 4 3 2 1 0
Старший бит ——▶ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ◀—— Младший бит
▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲
│ │ │ │ │ │ │ │
Бит защиты от чтения ╯ │ │ │ │ │ │ ╰ Резервированный бит
Резервированный бит ──╯ │ │ │ │ │
│ │ │ │ ╰── "Скрытый" файл, защищен от команды просмотра каталога
Архивный файл ──╯ │ │ ╰──── Системный файл с особым доступом
Подкаталог ────╯ ╰──── Метка тома
//Бит 0// в системе [[msx:dos:|]] зарезервирован.
//Биты 1-й и 2-й// служат для индикации атрибутов "скрытого" и "системного" файла. //Первый// бит байта атрибутов, установленный в 1, определяет "скрытый" файл, а //второй// бит, установленный в 1, — системный файл.
Таким образом, "видимый" файл будет иметь нулевой байт атрибута (00000000),
для "скрытого" файла байт атрибута содержит значение 2 (00000010),
для системного файла байт атрибута содержит значение 4 (00000100),
а для "скрытого" системного файла байт атрибута содержит значение 6 (00000110).
Хотя обработка системного атрибута осуществляется независимо от скрытого, оба этих атрибута практически совпадают по своему функциональному назначению. При использовании любого из них файл становится "невидимым".
Если //бит 1// или //бит 2// равен 1, то файл исчезает из каталога. Его нельзя ни стереть, ни прочитать, т.к. при всяком обращении к нему операционная система сообщает: "File not found".
//Бит 3// (содержимое байта атрибутов: 00001000) указывает, что элемент Справочника содержит метку тома. Сама метка хранится в полях имени файла и расширения, которые воспринимаются в этом случае как одно целое.
Если бит 3 равен 1, то файл исчезает из каталога. Его нельзя ни стереть, ни прочитать, т.к. при всяком обращении к нему говорится: "File not found"
В операционной системе [[msx:dos:|]] //бит 4// (содержимое байта атрибутов: 00010000) используется для указания элементов Справочника, соответствующих Справочникам нижнего уровня. Поскольку Справочники нижнего уровня хранятся на диске подобно обычным файлам данных, им необходим собственный элемент в корневом Справочнике. В этом элементе используются все поля, кроме размера файла, в данном случае равного нулю. Действительный размер файла Справочника нижнего уровня легко определяется из соответствующей последовательности в Таблице Размещения Файлов.
В операционной системе [[msx:dos:|]] равенство бита 4 единице приводит к тому, что при просмотре каталога командой ''DIR'', Вы увидите на экране слово ''
Время = Часы×2048+Минуты×32+Секунды/2
23–й байт 22–й байт
┌───┬───┬───┬───┬───┬───┬───┬───┐ ┌───┬───┬───┬───┬───┬───┬───┬───┐
│ h4│ h3│ h2│ h1│ h0│ m5│ m4│ m3│ │ m2│ m1│ m0│ s4│ s3│ s2│ s1│ s0│
└───┴───┴───┴───┴───┴───┴───┴───┘ └───┴───┴───┴───┴───┴───┴───┴───┘
╰───────────────────┼───────────────────────────┼───────────────────╯
Часы (0÷23) Минуты (0÷59) Секунды/2 (0÷29)
Дата = (Год-1980)×512+Месяц×32+День
Диапазон значений лет составляет от 1980 до 2079, причем хранятся они в виде относительных величин от 0 до 99. Хотя формат позволяет задавать относительный номер года 127 (что соответствует 2107 году), операционная система [[msx:dos:|]] позволяет работать с годами только до 2079.
Никто, правда, не ожидает, что [[msx:dos:|]] будет использоваться так долго!
25-й байт 24-й байт
┌───┬───┬───┬───┬───┬───┬───┬───┐ ┌───┬───┬───┬───┬───┬───┬───┬───┐
│ y6│ y5│ y4│ y3│ y2│ y1│ y0│ m3│ │ m2│ m1│ m0│ d4│ d3│ d2│ d1│ d0│
└───┴───┴───┴───┴───┴───┴───┴───┘ └───┴───┴───┴───┴───┴───┴───┴───┘
╰───────────────────────────┼───────────────────┼───────────────────╯
Годы (0÷99) Месяцы (1÷12) Дни (1÷31)
Как формат, так и размещение полей даты и времени подобраны таким образом, чтобы вместе они образовывали единое четырехбайтовое поле, которое можно использовать в операциях сравнения. Достаточно просто извлекать компоненты даты и времени из соответствующих полей и вычислять
их разность.
Например, для разделения даты на составные части можно использовать следующие формулы, записанные на языке программирования Pascal:
Год:=1980+поле_даты div 512
Месяц:=(поле_даты mod 512) div 32
День := поле_даты mod 32
//Номер начального кластера//. Это двухбайтовое поле содержит шестнадцатиразрядное число, являющееся смещением до начальной точки файла в Таблице Размещения Файлов.
//Размер файла//. Это поле состоит из четырех байтов. Размер файла задается в байтах и хранится в формате четырехбайтового целого числа без знака. Размер файла не всегда указывает точное число байтов. Для всех файлов это поле должно соответствовать размеру файла в секторах.
Для программных файлов, представленных в виде "COM"–файла и для файлов, созданных из данных фиксированной длины, только поле размера файла позволяет точно определить, где находится конец данных. Для этих файлов значение в поле размера файла хранится с точностью до байта.
Для файлов некоторых других форматов такая точность не обязательна и размер файла, указанный в соответствующем поле, может отличаться от действительного. Наиболее часто это случается с текстовыми файлами.
Текстовые файлы в кодах ASCII имеют маркер (признак) конца файла, хранящийся в самом файле, который фиксирует точный конец данных.
{{anchor:n123e}}
=== Примеры, взятые из жизни ===
A>copy con batch.bat
(перед именем ''batch.bat'' не было указано имя дисковода ''В'').
С консоли создали некоторый текстовый файл и нажали клавиши
Write protect error writing drive A:
Abort, Retry, Ignore?
Номер_первого_кластера_последнего_файла + (Его_объем div 400h) + 1 ,
(все вычисления производятся в шестнадцатеричной системе).
Распечатали оглавление диска (этого можно не делать) и установили признаки концов файлов в соответствии с каталогом по формуле:
Последний_кластер_файла = Начальный_кластер - 1
0000h ┬────────────────────────────────────────────────┐
│▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧│
│▧▧▧▧▧▧▧▧▧ ROM (Интерпретатор MSX-BASIC) ▧▧▧▧▧▧▧│
│▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧▧│
8000h ┼────────────────────────────────────────────────┤
│ Программа на языке BASIC │
│ ("Program Instruction Table", PIT) │
├────────────────────────────────────────────────┤
│ Простые переменные ("Variable Table") │
├────────────────────────────────────────────────┤
│ Массивы ("Array Variable Table") │
├────────────────────────────────────────────────┤
│ Свободная область ("Free Area") │
├────────────────────────────────────────────────┤
│ Стек ("Stack Area") │
├────────────────────────────────────────────────┤
│ Строковая область ("Character String Area") │
├────────────────────────────────────────────────┤
│ Блок управления файлами ("Files Control Block")│
F380h ┼────────────────────────────────────────────────┤
│ Рабочая область │
│ (системные переменные и таблица ловушек) │
FFFFh ┴────────────────────────────────────────────────┘
Таблица PIT обычно начинается по адресу &H8000. Однако ее можно "сдвинуть", изменив значение системной переменной TXTTAB в таблице системных переменных. Для помещения PIT с адреса &HА000 достаточно выполнить следующую программу:
5 'Адрес &HА001, находящийся в двух ячейках с номерами,
начиная с &hF676, определяет место, с которого начнется текст программы.
10 POKE &HF676,&H01 'Заполнение младшего байта слова TXTTAB
20 POKE &HF677,&HA0 'Заполнение старшего байта слова TXTTAB
30 POKE &HA000,0 'Первый байт PIT(&HA000) должен быть нулевым!
40 NEW 'Стираем данную программу!
Напомним Вам, что адрес &HА001 ( как и любой другой! ) размещается в двух байтах так:
Адрес ——▶ &HF676 &HF677 ◀—— Адрес
младшего байта │ │ старшего байта
┌─────│─────────│────┐
Содержимое │ ┌───▼──┐ ┌───▼──┐ │ Содержимое
младшего ◀————— &Н01 │ │ &HА0 —————▶ старшего
байта │ └──────┘ └──────┘ │ байта
└────────────────────┘
Очевидно, что в результате этих "манипуляций" размер свободной области уменьшится на &H2000 байтов (&HA000-&H8000=&H2000), и область, расположенная между &H8000 и началом PIT, будет защищена от "вторжения" программ на [[msx:basic:|]]. Ясно, что величина PIT зависит от размера текста программы. После выполнения данной программы нажмите кнопку сброса "RESET". А теперь мы поведаем Вам о том, как хранится программа, написанная на языке [[msx:basic:|]] в PIT.
10 B=5
20 END
Теперь прочитаем, что же реально содержится в PIT, используя в непосредственном режиме команду
PRINT HEX$(PEEK(A))
┌───────────┬─────────────┬───────────────────────────────────────────┐
│ Значение А│HEX$(PEEK(A))│ Комментарии │
├───────────┼─────────────┼───────────────────────────────────────────┤
│ 8000 │ 0 │ Первый байт PIT всегда нулевой │
├───────────┼─────────────┼───────────────────────────────────────────┤
│∙∙ 8001 ∙∙│ 09 │ Ссылка на начало следующей строки │
│∙∙ 8002 ∙∙│ 80 │ (указатель следующей строки находится по │
│∙∙∙∙∙∙∙∙∙∙∙│ │ адресу &Н8009) │
├───────────┼─────────────┼───────────────────────────────────────────┤
│ 8003 │ А │ "Визуальный" номер первой строки │
│ 8004 │ 0 │ &H000А = 10 │
├───────────┼─────────────┼───────────────────────────────────────────┤
│ 8005 │ 42 │ Шестнадцатеричный код ASCII буквы "B" │
│ 8006 │ EF │ Внутренний код знака равенства │
│ 8007 │ 16 │ Внутренний код цифры 5 │
│ 8008 │ 0 │ Конец первой строки │
├───────────┼─────────────┼───────────────────────────────────────────┤
│∙∙ 8009 ∙∙│ 0F │ Ссылка на начало следующей строки │
│∙∙ 800A ∙∙│ 80 │ (указатель следующей строки находится по │
│∙∙∙∙∙∙∙∙∙∙∙│ │ адресу &Н800F) │
├───────────┼─────────────┼───────────────────────────────────────────┤
│ 800B │ 14 │ "Визуальный" номер первой строки │
│ 800C │ 00 │ &H0014 = 20 │
├───────────┼─────────────┼───────────────────────────────────────────┤
│ 800D │ 81 │ Внутренний код оператора END │
│ 800Е │ 00 │ Конец второй строки │
├───────────┼─────────────┼───────────────────────────────────────────┤
│ 800F │ 0 │ Конец программы │
│ 8010 │ 0 │ │
└───────────┴─────────────┴───────────────────────────────────────────┘
Теперь, надеемся, Вам стало ясно, как можно изменить программу с помощью оператора POKE.
Попробуйте выполнить следующее:
POKE &H8005,&H41 '41 - шестнадцатеричный код ASCII буквы "A"
POKE &H8007,&H17 '17 - внутренний код цифры "6"
А теперь наберите команду ''LIST'', затем нажмите клавишу
10 A=6
20 END
Теперь Вам ясно, что "инструкции" ''PEEK'' и ''POKE'' таят в себе поистине безграничные возможности. По существу, они позволяют нам распоряжаться памятью компьютера по своему усмотрению.
Например, они позволяют нам при желании подшутить над компьютером: если известно, где хранится программа, то мы можем сделать так, что после одной из строк программы окажется строка с меньшим номером.
Пусть исходная программа имеет вид:
10 PRINT 4
20 PRINT 2
Вам, конечно, уже известно, что строки программы на языке [[msx:basic:|]] начинаются с двухбайтного указателя, за которым следуют два байта, содержащие номер строки. Поэтому вначале выполним команду:
PRINT HEX$(PEEK(&H8002));" ";HEX$(PEEK(&H8001))
80 9
Ok
Таким образом, указатель следующей (с номером 20) строки располагается в ячейках с адресами &H8009 и &H800A, а, следовательно, номер второй строки находится в ячейках с адресами &H800B и &H800C.
Проверим этот факт:
PRINT HEX$(PEEK(&H800C));" ";HEX$(PEEK(&H800B)) ╭──▶ PRINT &H14
0 14 ────────────────────────────────────────────╯ 20
Ok Ok
А теперь:
POKE &H800B,1
Ok
list
10 PRINT 4
1 PRINT 2
Ok
Программа действует, но строку с номером 1 нельзя ни стереть, ни исправить. Вы можете написать еще одну 1–ю строку и даже новую 20–ю строку!
Однако не пытайтесь изменять с помощью оператора ''POKE'' длину строки или путать указатели: результат будет катастрофическим!
Ну а если Вы нечаянно нажали RESET, — не спешите отчаиваться! Вашу программу еще можно спасти. Это очень легко сделать, набрав ту же команду
POKE &H8001,1
а затем
auto
10*
20* и так далее ...
Строки с ''*'' — спасенные. Теперь достаточно "скомандовать": ''LIST'' и... о, чудо! Но это еще не все! Оказывается, спасены и все строки между теми, номера которых не делятся нацело на 10!
Если же Вы захотите защитить свою программу от запуска(команды ''RUN''), то примените в непосредственном режиме команду:
POKE &H8000,1
Ok
(разумеется, Ваша программа должна располагаться с адреса &H8000).
По команде ''SAVE'' компьютер выполняет следующие простые действия...
Программа сохраняется в файле на диске таким образом:
* α) значение первого байта файла устанавливается в &HFF и
* β) текст программы во внутреннем представлении копируется из PIT на дискету.
Надеемся, что эти примеры немного развлекли Вас и переходим к цели нашего повествования...
Пример номер два
На диске находилась сложная программа, сохраненная во внутреннем коде. Однажды "Некто" под тем же именем сохранил пустую программу. Копии большой программы не было, и по этому ее нужно было восстановить во что бы то ни стало.
При просмотре диска мы обнаружили некоторые интересные вещи:
- 1) объем файла стал равным трем байтам (содержимое: FF,00,00);
- 2) за этими тремя байтами следовали еще 253 неизвестных байта;
- 3) остальная информация сохранилась полностью, восстановления требовали только FAT и директории.
Программу можно было попытаться спасти,но вызывал затруднения следующий нюанс: содержимое "испорченного" сектора будет "портить" всю программу; при использовании команды ''LIST'' на экране может появиться все, что угодно, но только не Ваша программа!
Как избежать этого? Логично было бы вручную исправить начальный сектор файла таким образом, чтобы не потерять ни одной ссылки, ни одного байта из оставшейся части программы.
Восстановление началось с того, что мы определили цепочку ссылок в FAT, вписали прежний размер файла в каталог и сохранили все это на диске. Затем необходимо было чем-то заполнить первые 256 байт, чтобы потом эту программу можно было загрузить в [[msx:basic:|]]–системе. Помня, что в строке может быть не более 255 символов, мы сделали 2 строчки, заполнили их кодами &HF1 (внутренний код символа "+") и расставили ссылки на следующие строки. Весь сектор (256 байт) был заполнен примерно таким образом:
┌────────────┬────────────────────────────────────────┐
│ Адрес байта│ Содержимое │
├────────────┼────────────────────────────────────────┤
│ 000 │ FF — первый стандартный для │
│ │ файлов на BASIC байт │
├────────────┼────────────────────────────────────────┤
│ 001 │ 05 ╮ 8105 — адрес след. строки │
│ 002 │ 81 ╯ │
├────────────┼────────────────────────────────────────┤
│ 003 │ 01 ╮ 0001 — номер строки │
│ 004 │ 00 ╯ │
├────────────┼────────────────────────────────────────┤
│ 005 │ F1 ╮ │
│ │ │ │
│ ∙∙∙ │ ∙∙∙ │ строка из 255 символов "+" │
│ │ │ │
│ 103 │ F1 ╯ │
│ 104 │ 00 — конец строки │
├────────────┼────────────────────────────────────────┤
│ 105 │ FC ╮ 81FC — адрес след. строки │
│ 106 │ 81 ╯ │
├────────────┼────────────────────────────────────────┤
│ 107 │ 02 ╮ 0002 — номер строки │
│ 108 │ 00 ╯ │
├────────────┼────────────────────────────────────────┤
│ 109 │ F1 ╮ │
│ │ │ │
│ ∙∙∙ │ ∙∙∙ │ строка из 242 символов "+" │
│ │ │ │
│ 1FA │ F1 ╯ │
│ 1FB │ 00 — конец строки │
├────────────┼────────────────────────────────────────┤
│ 1FC │ ?? ╮ 82?? — неизвестный адрес │
│ 1FD │ 82 ╯ след. строки (его определяют │
│ │ по содержимому 2-го сектора) │
├────────────┼────────────────────────────────────────┤
│ 1FE │ 03 ╮ 0003 — номер строки │
│ 1FF │ 00 ╯ │
└────────────┴────────────────────────────────────────┘
Обратите внимание на тот факт, что адресу 1FC должна лежать ссылка на существующую строку программы, поэтому перед тем, как заполнить этот байт, Вы должны внимательно просмотреть начало следующего сектора (приблизительно 252 байта) и найти адрес (в разделе ENTRY) байта, стоящего перед байтом с содержимым 82h!
Только после этого можно загружать программу в [[msx:basic:|]] и, уничтожив две первые строки, вспоминать, каким было начало Вашей программы!
{{anchor:n124}}
==== I.2.4. Область данных на дискете. Размещение файлов ====
┌─────────────────┬───────┬───────┬───────┬─────┬─────────┬─────────┐
│ Номера секторов │0Ch÷0Dh│0Eh÷0Fh│10h÷11h│ ... │59Bh÷59Ch│59Dh÷59Eh│
├─────────────────┼───────┼───────┼───────┼─────┼─────────┼─────────┤
│ Номер кластера │ 02h │ 03h │ 04h │ ... │ 712h │ 713h │
└─────────────────┴───────┴───────┼───────┴─────┴─────────┴─────────┘
Номер первого кластера с содержимым файла находится в Справочнике диска. Ссылки на остальные кластеры находятся в Таблице Размещения Файлов.
Работая с Таблицей Размещения Файлов можно легко восстановить файл, стертый командой ''DEL'' или любой аналогичной командой, т.к. при уничтожении файла происходит следующее:
- код первого символа имени файла устанавливается равным E5h;
- стирается (обнуляется) вся информация в FAT, относящаяся к этому файлу, а место в ней освобождается для информации о новом файле;
- информация из "стертого" файла сохраняется на дискете до тех пор, пока на дискету не будет записан новый файл. И до тех пор, пока на диск не записан новый файл, старый файл //можно восстановить// (если, конечно, Вы знаете, в каких кластерах он размещался до "стирания"!).
Теперь мы можем рассмотреть метод выделения кластеров для файлов.
При записи на дискету данных из файла для них по одному выделяются кластеры дискеты. Когда необходим очередной кластер для данных, то выбирается доступный кластер с наименьшим номером. Такая простая схема используется как при создании файла, так и при его "удлинении" (путем добавления данных в конец файла).
Операционная система [[msx:dos:|]] выделяет место на дискете по одному кластеру, когда в этом есть необходимость, не заботясь о том, чтобы все данные файла хранились в одной непрерывной области диска. При разработке любой схемы распределения дискового пространства в любой операционной системе приходится выбирать между свободным выделением пространства по одному кластеру (в результате файл может оказаться "размазанным" по всей дискете), и выделением места большими непрерывными сегментами, что усложняет задачу управления пространством на дискете. Операционная система [[msx:dos:|]] использует более простой первый метод.
Если дискета пуста, то все доступное на ней место представляет собой одну большую "чистую" область. Когда файлы копируются на такую дискету, они оформляются в виде удобно размещенных //непрерывных// сегментов дискового пространства. Но впоследствии, если файлы будут "удлиняться", то дополнительное место будет выделяться в первых свободных кластерах, которые могут находиться в //любом// месте дискеты.
Когда файлы копируются на новую дискету и не изменяются программистом, их размещение на диске остается экономичным. Но если создаются или удаляются какие-либо данные, то использование места на дискете становится весьма запутанным. Это очень часто происходит, когда программа
создает одновременно два файла. Если файлы увеличиваются параллельно, то их расположение на дискете обязательно будет перемежающимся.
Итак, при распределении пространства на дискете операционная система [[msx:dos:|]] равномерно использует все пространство и не требует Вашего вмешательства. Однако все эти преимущества достигаются ценой "размазывания" файлов по дискете. Из-за этого может увеличиться время доступа к файлу, поскольку магнитная головка чтения-записи должна перемещаться по всей дискете для поиска нужных треков. Поскольку обращения к дискете являются наиболее медленными операциями и основными факторами, ограничивающими производительность компьютера, такое размещение файлов может породить проблемы, хотя обычно этого не случается.
По этой причине необходимо уделять внимание потенциальной проблеме фрагментации пространства, занимаемого файлами на дискете. В тех случаях, когда фрагментация файлов покажется Вам нежелательной, скопируйте файл на новую дискету. Это же полезно делать, если Вам покажется, что дисковод слишком долго выполняет поиск треков при чтении файла.
При копировании файлов на новую дискету можно заодно улучшить их последовательность, разместив в начале часто использующиеся файлы или переставив их в таком порядке, в каком Вам хотелось бы их видеть в распечатке содержимого дискеты.
Теперь мы расскажем Вам о структуре текстовых файлов.
//Текстовый файл в коде ASCII// — это наиболее часто использующийся и один из самых важных форматов для файлов данных, размещаемых на дискетах. Такие файлы содержат обычную алфавитную информацию, тексты или отчеты, состоящие из алфавитных символов.
//Большинство текстовых редакторов используют текстовый формат//. Текстовый формат используется для хранения исходного текста программ (исходной, нетранслировавшейся версии). Практически все языковые процессоры (такие, как интерпретатор языка [[msx:basic:|]], компилятор языка Pascal или Макроассемблер) ожидают ввода файла в текстовом формате.
//Вообще говоря, имеется три различных категории кодов ASCII и две из них будут нас интересовать//.
//Одна// категория используется для кодировки данных, таких как буквы, цифры и знаки пунктуации.
┌───┬─────┬───┬─────┬───┬─────┬───┬─────┬───┬─────┬───┬─────┬───┬─────┐
│Код│Клав.│Код│Клав.│Код│Клав.│Код│Клав.│Код│Клав.│Код│Клав.│Код│Клав.│
├───┼─────┼───┼─────┼───┼─────┼───┼─────┼───┼─────┼───┼─────┼───┼─────┤
│ 32│SPACE│ 55│ 7 │ 78│ N │101│ e │124│ | │211│ с │234│ Й │
│ 33│ ! │ 56│ 8 │ 79│ O │102│ f │125│ } │212│ т │235│ К │
│ 34│ " │ 57│ 9 │ 80│ P │103│ g │126│ ~ │213│ у │236│ Л │
│ 35│ # │ 58│ : │ 81│ Q │104│ h │191│ ¤ │214│ ж │237│ М │
│ 36│ $ │ 59│ ; │ 82│ R │105│ i │192│ ю │215│ в │238│ Н │
│ 37│ % │ 60│ < │ 83│ S │106│ j │193│ а │216│ ь │239│ О │
│ 38│ & │ 61│ = │ 84│ T │107│ k │194│ б │217│ ы │240│ П │
│ 39│ ' │ 62│ > │ 85│ U │108│ l │195│ ц │218│ з │241│ Я │
│ 40│ ( │ 63│ ? │ 86│ V │109│ m │196│ д │219│ ш │242│ Р │
│ 41│ ) │ 64│ @ │ 87│ W │110│ n │197│ е │220│ э │243│ С │
│ 42│ * │ 65│ A │ 88│ X │111│ o │198│ ф │221│ щ │244│ Т │
│ 43│ + │ 66│ B │ 89│ Y │112│ p │199│ г │222│ ч │245│ У │
│ 44│ , │ 67│ C │ 90│ Z │113│ q │200│ х │223│ ъ │246│ Ж │
│ 45│ - │ 68│ D │ 91│ [ │114│ r │201│ и │224│ Ю │247│ В │
│ 46│ . │ 69│ E │ 92│ \ │115│ s │202│ й │225│ А │248│ Ь │
│ 47│ / │ 70│ F │ 93│ ] │116│ t │203│ к │226│ Б │249│ Ы │
│ 48│ O │ 71│ G │ 94│ ^ │117│ u │204│ л │227│ Ц │250│ З │
│ 49│ 1 │ 72│ H │ 95│ _ │118│ v │205│ м │228│ Д │251│ Ш │
│ 50│ 2 │ 73│ I │ 96│ ` │119│ w │206│ н │229│ Е │252│ Э │
│ 51│ 3 │ 74│ J │ 97│ a │120│ x │207│ о │230│ Ф │253│ Щ │
│ 52│ 4 │ 75│ K │ 98│ b │121│ y │208│ п │231│ Г │254│ Ч │
│ 53│ 5 │ 76│ L │ 99│ c │122│ z │209│ я │232│ Х ├───┴─────┘
│ 54│ 6 │ 77│ M │100│ d │123│ { │210│ р │233│ И │
└───┴─────┴───┴─────┴───┴─────┴───┴─────┴───┴─────┴───┴─────┘
//Вторая// категория используется для форматирования, т.е. для указания места, где заканчивается одна строка и начинается другая; эти коды используются не только для управления форматом печати, но и для структурирования файлов.
И, наконец, //третья// категория служит для управления передачей данных и никак не связана с форматом текстовых файлов.
Символы ASCII двух специальных категорий — форматирующие и символы связи, — имеют коды от 0 до 31 и 127.
┌─────┬───────────────┬─────┬───────────────┬─────┬───────────────┐
│ Код │ Клавиша (и) │ Код │ Клавиша (и) │ Код │ Клавиша (и) │
├─────┼───────────┼───┼─────┼───────────────┼─────┼───────────────┤
│ 0 │ CTRL+@ │ 11 │ CLS/HOME │ 22 │ CTRL+V │
│ 1 │ CTRL+A │ 12 │ CTRL+L │ 23 │ CTRL+W │
│ 2 │ CTRL+B │ 13 │ RETURN │ 24 │ SELECT │
│ 3 │ CTRL+C │ 14 │ CTRL+N │ 25 │ CTRL+Y │
│ 4 │ CTRL+D │ 15 │ CTRL+O │ 26 │ CTRL+Z │
│ 5 │ CTRL+E │ 16 │ CTRL+P │ 27 │ ESC │
│ 6 │ CTRL+F │ 17 │ CTRL+Q │ 28 │ ———▶ │
│ 7 │ CTRL+G (BEEP) │ 18 │ INS │ 29 │ ◀——— │
│ 8 │ BS │ 19 │ CTRL+S │ 30 │▲ стрелка вверх│
│ 9 │ TAB │ 20 │ CTRL+T │ 31 │▼ стрелка вниз │
│ 10 │ CTRL+J (LF) │ 21 │ CTRL+U │ 127 │ DEL │
└─────┴───────────────┴─────┴───────────────┴─────┴───────────────┘
Теперь рассмотрим структуру //текстового// файла в коде ASCII. Символы текстового файла организуются в //строки//, подобно строкам на бумаге. Границы строк отмечаются форматирующими символами кода ASCII:
* //возврат каретки// — символ с кодом 13 (0Dh) и
* //перевод строки// — символ с кодом 10 (0Ah).
Можно было бы использовать любой символ для обозначения конца строки, но используются именно эти два символа, поскольку они управляют процессом перехода к новой строке на печатающем устройстве.
Одной из причин использования двух символов, обозначающих конец строки, состоит в обеспечении возможности наложения строк. Наиболее часто такая возможность используется для выполнения подчеркивания. При этом на печать в конце строки выдается только символ "возврат каретки", а затем накладывающиеся символы. Поскольку перевод строки не выполнялся, новые символы печатаются поверх уже напечатанных. Однако заметим, что такую операцию можно произвести с печатающим устройством, но нельзя с дисплеем.
Формат текстового файла определяется не только разделением на строки. Все файлы в коде ASCII имеют один общий символ //маркер конца файла//, код ASCII которого равен 26 (1Ah). Этот маркер однозначно указывает конец файла. Обнаружение положения кода 26 позволяет точно установить
размер файла, отличающийся от размера, указанного в Справочнике.
----
[<>]
{{tag>msxfdfss}}