Лабораторная работа № 17-18. «Получение навыков в работе с таблицей размещения файлов». Краткие теоретические и учебно-методические материалы
Лабораторная работа № 17-18
«Получение навыков в работе с таблицей размещения файлов» Цель работы: получение практических навыков в работе с таблицей размещения файлов. Образовательные результаты, заявленные во ФГОС третьего поколения: Студент должен уметь: - осуществлять разработку кода программного модуля на современных языках программирования; - создавать программу по разработанному алгоритму как отдельный модуль; - выполнять отладку и тестирование программы на уровне модуля знать: - основные этапы разработки программного обеспечения; - основные принципы технологии структурного и объектно-ориентированного программирования; - основные принципы отладки итестирования программных продуктов. Краткие теоретические и учебно-методические материалы по теме лабораторной работы В 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 - 2024 megalektsii.ru Все авторские права принадлежат авторам лекционных материалов. Обратная связь с нами...
|