![]() |
Главная Случайная страница Контакты | Мы поможем в написании вашей работы! | |
|
В DOS имеются два совершенно независимых метода работы с файлами: метод Управляющих Блоков Файлов (FCB - File Control Block) и метод файловых дескрипторов (Handle - переводится также как файловые описатель, файловое число, файловый индекс).
При использовании метода файловых дескрипторов в операциях, связанных с открытием файла, задает ASCIIZ -строку, содержащую имя файла (если файл находится не в текущем каталоге, строка содержит и полный путь). При успешном открытии файла функция возвращает файловый дескриптор (целое число) который является идентификатором открытого файла во всех других операциях с файлом. Метод файловых дескрипторов отличает простота использования, возможность работы с файлами, находящимися не в текущем каталоге, единообразие при работе с дисковыми файлами и файлами - символьными устройствами.
Метод FCB использует так называемую Дисковую Передаточную Область (DTA - Disk Transfer Area). При загрузке программы эта область выделяется программе системой, но программист может организовать собственную DTA и сообщить системе ее адрес. Весь обмен с дисками ведется только через DTA - назначенную системой или установленную программистом. Это, однако, не требует обязательной пересылки данных между DTA и рабочими областями программы, так как программист может в любой момент переназначить адрес DTA на свою рабочую область.
Пример:
Определить номера всех кластеров диска, которые занимает заданный преподавателем файл в текущем каталоге.
Программа состоит из главной функции main() и одиннадцати вспомогательных функций.
void Read_Mbr(void) - функция чтения MBR и поиска требуемого раздела.
void Read_Boot(void) - функция чтения boot-сектора.
void Get_First(void) - функция определения абсолютного номера сектора начала логического диска.
void Read_Fat(void) - функция чтения FAT.
void Read_13(void *mem) - функция чтения сектора с помощью прерывания 13.
void Sect_to_Daddr(dword sect) - функция формирования физического дискового адреса из номера сектора.
dword Clust_to_Sect(word clust) - функция определения номера сектора по номеру кластера.
word Next_Clust(word clust) - функция выборки следующего кластера из FAT.
char *Get_Name(char *s, char *d) - функция выделения следующего элемента из строки-задания.
int Find_Name() - функция поиска имени в каталоге.
void End_of_Job(int n) - функция выдачи сообщений или аварийного завершения.
В программе описаны структуры такого вида:
Физический дисковый адрес:
struct DADDR {
byte h; /* головка */
word s, /* сектор */
t, /* дорожка */
ts; /* сектор, дорожка упакованные */
};
Структура элемента раздела;
struct PART {
byte Boot, /* признак активного */
/* физический адрес начала раздела */
Begin_Hd; /* # головки */
word Begin_SecTrk; /* # сектора и дорожки */
byte SysCode, /* код системы */
/* физический адрес конца раздела */
End_Hd; /* # головки */
word End_SecTrk; /* # сектора и дорожки */
dword RelSec, /* # сектора початку */
Size; /* количество секторов */
};
Стpуктуpа Главной Загрузочной Записи:
struct MBR
{
char LoadCode[0x1be]; /* программа загрузки */
struct PART rt[4]; /* 4 элемента разделов */
word EndFlag; /* подпись MBR */
};
Структура загрузочной записи логического диска:
struct BootRec {
byte jmp[3], ident[8];
word SectSize;
byte ClustSize;
word ResSect;
byte FatCnt;
word RootSize, TotSecs;
byte Media;
word FatSize, TrkSecs, HeadCnt;
word HidnSecL, HidnSecH;
dword LongTotSecs;
byte Drive, reserved1, DOS4_flag;
dword VolNum; char VolLabel[11], FatForm[8];
};
Структура элемента каталога:
struct Dir_Item {
char fname[11]; /* имя файла */
byte attr; /* атрибут */
byte reserved[10];
word time; /* время */
word date; /* дата */
word cl; /* номер 1-го кластера */
dword size; /* размер файла */
};
Переменные, глобальные для всей программы:
part - текущий элемент раздела;
buff1[512] - буфер MBR и boot;
*mbr - указатель на таблицу разделов;
*boot - указатель на корневую запись;
buff2[512] - буфер каталога и текста;
*dir - указатель на часть каталога;
*text - указатель на текстовый буфер;
*fat - указатель на FAT;
job[81] - строка-задание;
jobptr - текущий указатель в job;
cname[12] - текущее имя для поиска;
Fdisk - физический номер диска;
caddr - текущий дисковый адрес;
sect - текущий номер сектора;
clust - текущий номер кластера;
fat16 - признак формата FAT;
fsize - размер файла;
dirnum - номер элемента в каталоге;
FirstSect - абсолютный номер сектора начала;
rootdir=1 - признак корневого каталога или подкаталога (1/0);
lastsect - последний сектор при чтении;
fatalloc=0 - признак выделения памяти.
Функция main запрашивает имя файла, потом обрабатывает его и, если все нормально, то запускает вспомогательные функции необходимые для просмотра FAT заданного файла. Функция Read_Mbr выполняет выборку элемента таблицы разделов для заданного диска. Функция Read_Boot считывает boot-сектор логического диска, причем для гибкого диска адрес этого сектора назначается - 0, 0, 1, а для жесткого - выбирается из part. Функция Get_First определяет абсолютный номер начального сектора логического диска и сохраняет его переменной First_Sect. Это значение вычисляется из физического адреса начала, который берется из полей Begin_Hd, Begin_SecTrk элемента таблицы разделов. Функция Read_Fat считывает в память FAT целиком, адрес начала FAT на диске и ее размер определяются из ранее прочитанного boot-сектора.
Функция Read_13 читает один сектор с помощью прерывания BIOS. Функция Sect_to_Daddr преобразует номер логического сектора в физический адрес. Функция Clust_to_Sect преобразует номер кластера в номер сектора. Функция Next_Clust определяет номер следующего кластера, анализируя FAT. Для последнего кластера (и для корневого каталога) эта функция возвращает нулевое значение. Функция Get_Name предназначена для лексического разбора задания, она выделяет из задания очередное слово и переназначает jobptr. Пустое (NULL) значение jobptr - свидетельство об исчерпании задания. Функция Find_Name выполняет поиск имени в каталоге. Здесь cname - требуемое имя, функция возвращает индекс найденного элемента в массиве dir или (-1). Функция End_of_Job выполняет выдачу на экран различных сообщений при ошибках или при завершении программы.
/* Подключение стандартных заголовков */
#include <dos.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <conio.h>
#include <ctype.h>
/*-------------------------------------------------------------*/
/* Типи и структуры данных */
#define byte unsigned char
#define word unsigned int
#define dword unsigned long
#define daddr struct DADDR
struct DADDR { /* физический дисковый адрес */
byte h;
word s, t, ts;
};
struct PART { /* структура элемента раздела */
byte Boot, Begin_Hd;
word Begin_SecTrk;
byte SysCode, End_Hd;
word End_SecTrk;
dword RelSec, Size;
};
struct MBR
{ /* стpуктуpа Главной Загрузочной Записи */
char LoadCode[0x1be];
struct PART rt[4];
word EndFlag;
};
struct BootRec
{ /* структура корневой записи */
byte jmp[3], ident[8];
word SectSize;
byte ClustSize;
word ResSect;
byte FatCnt;
word RootSize, TotSecs;
byte Media;
word FatSize, TrkSecs, HeadCnt;
word HidnSecL, HidnSecH;
dword LongTotSecs;
byte Drive, reserved1, DOS4_flag;
dword VolNum;
char VolLabel[11], FatForm[8];
};
struct Dir_Item
{ /* структура элемента директории */
char fname[11];
byte attr;
char reserved[10];
word time, date, cl;
dword size;
};
/*-------------------------------------------------------------*/
/* Описания функций */
void Read_Mbr(void); /* Чтение MBR и поиск требуе-
мого раздела */
void Read_Boot(void); /* Чтение boot-сектора */
void Get_First(void); /* Определение абсолютного номе-
ра сектора начала логического
диска */
void Read_Fat(void); /* Чтение FAT */
void Read_13(void *mem); /* Чтение сектора с омогощью
прерывания 13 */
void Sect_to_Daddr(dword sect); /* Формирование физического дискового
адреса из # сектора */
dword Clust_to_Sect(word clust); /* Вычисление номера сектора
из номера кластера */
word Next_Clust(word clust); /* Выборка следующего кластера
из FAT */
char *Get_Name(char *s, char *d); /* Выделение следующего элемен-
та из строки-задания */
int Find_Name(); /* Поиск имени в каталоге */
void End_of_Job(int n); /* Завершение (при n=0-5 -
аварийное) */
/*-------------------------------------------------------------*/
/* Переменнi */
struct PART part; /* текущий элемент раздела */
byte buff1[512]; /* буфер MBR и boot */
struct MBR *mbr; /* указатель на таблицу разделов */
struct BootRec *boot; /* указатель на корневую запись */
byte buff2[512]; /* буфер каталога и текста */
struct Dir_Item *dir; /* указатель на часть каталога */
char *text; /* указатель на текстовий буфер */
byte *fat; /* указатель на FAT */
char job[81]; /* строка-задание */
char *jobptr; /* текущий указатель в job */
char cname[12]; /* текущее имя для поиска */
byte Fdisk; /* физический номер диска */
daddr caddr; /* текущий дисковый адрес */
dword sect; /* текущий номер сектора */
word clust; /* текущий номер кластера */
byte fat16; /* признак формату FAT */
dword fsize; /* размер файла */
int dirnum; /* номер элемента в каталоге */
dword FirstSect; /* абс.сектор начала */
byte rootdir=1; /* признак корневого каталога
или подкаталога (1/0) */
word lastsect; /* последний сектор при чтении */
byte fatalloc=0; /* признак выделения памяти */
/*-------------------------------------------------------------*/
main() {
int n,i;
textattr(14);
clrscr();
/* ввод имени файла */
cprintf(" Просмотр таблицы FAT. ");
cprintf("Укажите полное имя файла -->");
scanf("%s",job);
/* перевод в верхний регистр */
strupr(job);
/* проверка правильности идентификатора диска */
if ((!isalpha(job[0]))||(job[1]!=':')||(job[2]!='\\')) {
printf("%c%c%c -",job[0],job[1],job[2]);
End_of_Job(0);
}
textattr(10);
clrscr();
printf(" Лабораторная работа N17-18");
printf(" Дисковые структуры данных DOS.");
textattr(14);
cprintf("Файл %s в FAT занимает такие кластеры:\n",job);
jobptr=job+3;
if (job[0]>'A') {
/* для жесткого диска - физический номер и чтение MBR */
Fdisk=0x80;
Read_Mbr();
}
else /* для гибкого диска - физический номер */
Fdisk=job[0]-'A';
Read_Boot(); /* чтение boot-сектора */
Read_Fat(); /* чтение FAT */
dir=(struct Dir_Item *)buff2;
do { /* рух по каталогам */
if (!rootdir) clust=dir[dirnum].cl; /* начальный кластер */
/* выделение следующего элемента из строки-задания */
jobptr=Get_Name(jobptr,cname);
do { /* пока не дойдем до последнего кластера */
if (rootdir) { /* корневой каталог */
/* нач.сектор корневого кат. и количество секторов */
sect=boot->ResSect+boot->FatSize*boot->FatCnt;
lastsect=boot->RootSize*32/boot->SectSize+sect;
}
else { /* подкаталог */
sect=Clust_to_Sect(clust);
lastsect=boot->ClustSize+sect;
}
/* посекторное чтение всего корневого каталога
или одного кластера подкаталога */
for (; sect<lastsect; sect++) {
Sect_to_Daddr(sect);
Read_13(dir);
/* поиск имени в прочитанном секторе */
if ((dirnum=Find_Name())>=0) goto FIND;
}
/* до последнего кластера подкаталога */
}
while (clust=Next_Clust(clust));
/* весь каталог просмотрен, а имя не найдено - ошибка */
printf("%s -",cname);
if (jobptr==NULL) End_of_Job(4);
else End_of_Job(5);
FIND: /* имя найдено */
rootdir=0;
}
while (jobptr!=NULL);
/* найдено имя файла */
/* из каталога получеем 1-й кластер */
clust=dir[dirnum].cl;
textattr(7);
gotoxy(10,4);
cprintf("Нажимайте любую клавишу ");
cprintf(" пока не появится <КОНЕЦ ФАЙЛА>.");
textattr(12);
gotoxy(1,5);
cprintf("-<НАЧАЛО ФАЙЛА>");
gotoxy(1,6);
cprintf("L->");
i=0;
do {
i++;
if((i%10)==0) getch();
textattr(14+16);
cprintf("%4x",clust);
textattr(2);
cprintf("--->");
}
while (clust=Next_Clust(clust));
textattr(12);
cprintf("<КОНЕЦ ФАЙЛА>\n");
gotoxy(1,wherey());
textattr(15+3*16);
cprintf("Количество кластеров в файле: %u ",i);
End_of_Job(7);
}
/*-------------------------------------------------------------*/
/* Чтение MBR и поиск нужного раздела */
void Read_Mbr(void) {
int i;
char ndrive;
word *EndList;
caddr.h=0;
caddr.ts=1;
ndrive='C';
mbr=(struct MBR *)buff1;
NEXT: Read_13(buff1);
for (EndList=(word *)&mbr->rt[(i=0)];
(*EndList!=0xaa55)&&(mbr->rt[i].Size>0L);
EndList=(word *)&mbr->rt[++i]) {
if (mbr->rt[i].SysCode==5) {
caddr.h=mbr->rt[i].Begin_Hd;
caddr.ts=mbr->rt[i].Begin_SecTrk;
goto NEXT;
}
if (ndrive==job[0]) {
movmem(&mbr->rt[i],&part,sizeof(struct PART));
return;
}
else ndrive++;
}
/* требуемый раздел не найден */
printf("%c: -",job[0]);
End_of_Job(1);
}
/*-------------------------------------------------------------*/
/* Чтение boot-сектора */
void Read_Boot(void) {
if (Fdisk<0x80) {
caddr.h=0;
caddr.ts=1;
}
else {
caddr.h=part.Begin_Hd;
caddr.ts=part.Begin_SecTrk;
}
Read_13(buff1);
boot=(struct BootRec *)buff1;
Get_First();
}
/*-------------------------------------------------------------*/
/* Чтение FAT */
void Read_Fat(void) {
dword s, ls;
byte *f;
fat=(byte *)malloc(boot->FatSize*boot->SectSize);
if (fat==NULL) {
printf("Размещение FAT -");
End_of_Job(3);
}
fatalloc=1;
s=boot->ResSect;
ls=s+boot->FatSize;
for (f=fat; s<ls; s++) {
Sect_to_Daddr(s);
Read_13(f);
f+=boot->SectSize;
}
/* установление формата FAT */
if (Fdisk>=0x80)
if (part.SysCode==1) fat16=0;
else fat16=1;
else fat16=0;
}
/*-------------------------------------------------------------*/
/* Чтение сектора при помощи прерывания 13 */
void Read_13(void *mem) {
/* mem - адреса в ОП */
union REGS rr;
struct SREGS sr;
rr.h.ah=2;
rr.h.al=1;
rr.h.dl=Fdisk;
rr.h.dh=caddr.h;
rr.x.cx=caddr.ts;
sr.es=FP_SEG(mem);
rr.x.bx=FP_OFF(mem);
int86x(0x13,&rr,&rr,&sr);
/* Проверка ошибок чтения */
if (rr.x.cflag&1) {
printf("%u -",rr.h.ah);
End_of_Job(2);
}
}
/*-------------------------------------------------------------*/
/* Определение абс.номера сектора начала лог.диска */
void Get_First(void) {
word s, t;
if (Fdisk<0x80) FirstSect=0;
else {
/* формирование # сектора из физич. дискового адреса */
t=(part.Begin_SecTrk>>8)|((part.Begin_SecTrk<<2)&0x300);
s=part.Begin_SecTrk&0x3f;
FirstSect=(((dword)t*boot->HeadCnt)+part.Begin_Hd)*
boot->TrkSecs+s-1;
}
}
/*-------------------------------------------------------------*/
/* Формирование физического дискового адреса из # сектора */
void Sect_to_Daddr(dword sect) {
/* sect - номер сектора, caddr - адрес на диске */
dword s;
if (Fdisk>=0x80) sect+=FirstSect;
caddr.s=sect%boot->TrkSecs+1;
s=sect/boot->TrkSecs;
caddr.h=s%boot->HeadCnt;
caddr.t=s/boot->HeadCnt;
caddr.ts=(caddr.t<<8)|caddr.s|((caddr.t&0x300)>>2);
}
/*-------------------------------------------------------------*/
/* Вычисление номера сектора из номера кластера */
dword Clust_to_Sect(word clust) {
/* clust - номер кластера, возвращает номер сектора */
dword ds, s;
ds=boot->ResSect+boot->FatSize*boot->FatCnt+
boot->RootSize*32/boot->SectSize;
s=ds+(clust-2)*boot->ClustSize;
return(s);
}
/*-------------------------------------------------------------*/
/* Выборка следующего кластера из FAT */
word Next_Clust(word clust) {
/* clust - номер кластера, возвращает номер следующего кластера
или 0 - если следующего нет */
word m, s;
if (rootdir) return(0);
if (!fat16) {
m=(clust*3)/2;
s=*(word *)(fat+m);
if(clust%2) /* нечетный элемент */
s>>=4;
else /* четный элемент */
s=s&0x0fff;
if (s>0x0fef) return(0);
else return(s);
}
else {
m=clust*2;
s=*(word *)(fat+m);
if (s>0xffef) return(0);
else return(s);
}
}
/*-------------------------------------------------------------*/
/* Выделение следующего элемента из строки-задания */
char *Get_Name(char *s, char *d) {
/* s - строка задания, d - выделенный элемент, возвращает
указатель на новое начало строки задания. */
char *p,*r;
int i;
for(i=0;i<11;d[i++]=' ');
d[11]='\0';
if ((p=strchr(s,'\\'))==NULL) {
/* последний элемент строки - имя файла */
/* перезапись имени */
for(r=s,i=0; (i<8)&&*r&&(*r!='.'); i++,r++) *(d+i)=*r;
/* перезапись расширения */
if (*r) for(i=0,r++; (i<3)&&*r; i++,r++) *(d+8+i)=*r;
return(NULL);
}
else {
/* следующий элемент - имя подкаталога */
*p='\0';
for(r=s,i=0; (i<11)&&*r; i++,r++) *(d+i)=*r;
return(p+1);
}
}
/*-------------------------------------------------------------*/
/* Поиск имени в каталоге */
int Find_Name() {
int j;
/* cname - найденное имя; возвращает индекс найденного
элемента в массиве dir или (-1) */
for (j=0; j<boot->SectSize/sizeof(struct Dir_Item); j++) {
if (dir[j].fname[0]=='\0') {
/* конец использованных элементов каталога */
printf("%s -",cname);
if (jobptr==NULL) End_of_Job(4);
else End_of_Job(5);
}
if ((byte)dir[j].fname[0]!=0xe5) {
if (memcmp(dir[j].fname,cname,11)==0) {
/* если iм`я збiгатся, то:
- при поиске файла элемент не должен иметь атрибутов
"подкаталог" или "метка тома",
- при поиске подкаталога элемент должен иметь атрибут
"подкаталог" */
if (jobptr==NULL)
if (!(dir[j].attr&0x18)) return(j);
else
if (dir[j].attr&0x10) return(j);
}
}
}
return(-1);
}
/*-------------------------------------------------------------*/
/* Завершение (при n=0-5 - аварийное) */
void End_of_Job(int n) {
/* n - номер сообщения */
static char *msg[] = {
"неправильный идентификатор диска",
"логический диск отсутствует",
"ошибка чтения",
"нехватка памяти",
"подкаталог не найден",
"файл не найден",
"непредусмотренный конец файла",
"" };
/* освобождение памяти */
if (fatalloc) free(fat);
/* выдача сообщения */
textattr(12+128);
cprintf(" %s\n",msg[n]);
gotoxy(28,wherey());
cprintf(" Нажмите любую клавишу...\n");
textattr(7);
getch();
/* завершение программы */
exit(0);
}
В процессе работы программы на экран выводится информация наподобие следующей:
Файл D:\TC\TC.EXE в FAT занимает такие кластеры:
Нажимайте любую клавишу пока не появится <КОНЕЦ ФАЙЛА>.
-<НАЧАЛО ФАЙЛА>
8L->2410--->2411--->2412--->2413--->2414--->2415--->2416--->2417-
-->2418--->2419--->241a--->241b--->241c--->241d--->241e--->241f-
-->2420--->2421--->2422--->2423--->2424--->2425--->2426--->2427-
-->2428--->2429--->242a--->242b--->242c--->242d--->242e--->242f-
-->2430--->2431--->2432--->2433--->2434--->2435--->2436--->2437-
-->2438--->2439--->243a--->243b--->243c--->243d--->243e--->243f-
-->2440--->2441--->2442--->2443--->2444--->2445--->2446--->2447-
-->2448--->2449--->244a--->244b--->244c--->244d--->244e--->244f-
-->2450--->2451--->2452--->2453--->2454--->2455--->2456--->2457-
-->2458--->2459--->245a--->245b--->245c--->245d--->245e--->245f-
-->2460--->2461--->2462--->2463--->2464--->2465--->2466--->2467-
-->2468--->2469--->246a--->246b--->246c--->246d--->246e--->246f-
-->2470--->2471--->2472--->2473--->2474--->2475--->2476--->2477-
-->2478--->2479--->247a--->247b--->247c--->247d--->247e--->247f-
-->2480--->2481--->2482--->2483--->2484--->2485--->2486--->2487-
-->2488--->2489--->248a--->248b--->248c--->248d--->248e--->248f-
-->2490--->2491--->2492--->2493--->2494--->2495--->2496--->2497-
-->2498--->2499--->249a--->249b--->249c--->249d---><КОНЕЦ ФАЙЛА>
Количество кластеров в файле: 142
Задания для лабораторной работы:
Определить номера всех кластеров диска, которые занимает заданный преподавателем файл в текущем каталоге.
Контрольные вопросы:
1. Опишите методы работы с файлами.
2. Перечислите и дайте характеристику функций метода дескриптора.
3. Что такое раздел?
4. Что такое атрибуты каталога?
5. Что такое библиотека? Основные характеристики и назначение.
Дата публикования: 2015-11-01; Прочитано: 326 | Нарушение авторского права страницы | Мы поможем в написании вашей работы!