Saját file-kezelésünk alapjai: file
megnyitása, olvasása
Előző számunkban az objektumokat építettük
fel melyek megvalósítják a file-kezelést. Létrehoztuk a lemezt ill. az
Image-file-t kezelő objektumokat TPhisicalDrive / TImageDrive.
Ezek valósítják meg a szektorok beolvasását,
és egy logikai szektorkezelési felületet nyújtanak a file-kezelő objektumnak
esetünkben a TR4sFileDOS objektumnak.
Továbbá előző számunkban arról is szót
ejtettünk, hogy hogyan kell Image-file-t készíteni. Így elmondtam, hogy
szektorról-szektorra pontosabban track-ről – track-re (track = sáv) kell
lementeni a lemez tartalmát. Most szeretnék egy profibb megoldást kínálni
azok számára akik nincsenek megelégedve az image-file készítésének sebességével.
Majd ezek után az FCB-s file-kezelő utasításokat
kezdjük el.
Hogyan gyorsítsuk az Image-file elkészítését?
Előre ki kell ábrándítanom benneteket,
de csak azt a rendszert lehet gyorsítani, amin van mit gyorsítani. Így
nem minden lemezen fog gyorsulást eredményezni az alábbi rutin. Lássuk
az elvét, hogy hogyan működik:
-
Mitől lassú az image-file készítése?
Beolvassuk az összes track-et, s ez időt
vesz igénybe.
-
De miért olvassuk be mind a 160 (2*80) sávot?
-
Biztos, hogy mindegyik sávot be kell olvasnunk?
Ugye egy egyszerű lemezmásoló program ugyan
olyan fapados módszert használ, mint mi az előző számban. De most megmutatjuk,
hogy valójában hogy is kell ezt csinálni. [csak szerényen...
a szerk.]
A gyorsítás lényege, hogy ha nincs tele a lemez, akkor NEM kell mindent
beolvasni.
Bevallom töredelmesen én még nem találkoztam
olyan DOS-os lemezmásoló programmal ami ne olvasta volna be az egész lemezt
ha nem kell. Olyat viszont már láttam, ha a lemez végén összefüggő üres
hely van, akkor azt nem olvassa be. Nos hát ez egy eléggé rút megoldás
annál is inkább, hogy nem feltétlenül
biztos, hogy a lemez végén van az összefüggő üres hely. Pl. mi van, ha
a lemez közepén van 500 KB üres hely ?
Egy olyan megvalósítást írok le mely a 3.5" 1.44 MB kapacitású floppy-lemezeknél
gyorsítást eredményez. Teljes forráskódot nem közlök, csak a unit (MAKEIMG.INT)
Interface részét adom oda. (Akinek nagyon szüksége van a forráskódra, és
meg tud győzni, írjon: PC-XUSER@FREEMAIL.C3.HU)
Felhívnám a T. figyelmet, hogy ez egy több mint két éves unit-om, így
nem foglalkoztam vele mostanában, s csak a 1 sector / cluster –re
formázott kislemezeket kezeli megbízhatóan !!!
Miből áll a gyorsítás ?
-
Csak azt olvassuk be amit kell !
-
És honnét tudjuk mit kell beolvasni és mit nem ?
-
Hát a FAT-ból !
Nos ezen pár sort elolvasása után a Tisztelt
Olvasó csak legyint, hát ez ilyen egyszerű lenne ?
Persze sok más is áll a háttérben !
A figyelmesebbek elkezdenek gondolkozni, hogy álljunk csak meg egy szóra
!
-
Hisz a lemezt-image-t mi sávonkénti beolvasással hoztuk létre, mert így
a leggyorsabb.
-
Hááát és a FAT-ban pedig cluster (a DOS file-kezelésének legkisebb egysége)
szintű információk vannak eltárolva.
-
Vegyük a legáltalánosabb esetet, amikor 1 szektor alkot 1 cluster-t !
-
Ekkor már majdnem eljutunk odáig, hogy azt
a szektort kell csak beolvasni amelyiken információ van. Ezt meg egyszerűen
lekérdezhetjük a FAT-ból.
-
Persze fent említettem, hogy nem külön-külön szektorokat, hanem egy egész
sávot (track-et) olvasunk be. S ez megnehezíti dolgunkat.
Ugyanis tudnunk kell, hogy melyik sávon van
információ s melyiken nincs. Mert a gyorsaság megőrzése végett még mindig
sávokat olvasunk be egyszerre. Tehát amelyik sávon legalább egy szektornyi
információ van (egy szektor a 18-ból) azt ugyanúgy be kell olvasnunk akár
ha tele lenne a sáv mind a 18 szektorral. Nem látom értelmét csak pl. 10
szektor beolvasását, mert akkor oda is kell a fejet a kontrollernek pozícionálni
stb. s ez időt vesz el. Nem vagyok arról meggyőződve, hogy amennyi időt
nyerhetnénk a pl. 8 szektor be nem olvasásával az nem menne –e el
a plusz pozícionálással. (Itt persze nem csak a fejet kell mozgatni, hanem
meg kell várni amíg a lemeznek azon pontja forog be a fej alá amire szükség
van. Persze még vannak egyéb járulékos nem túl dokumentált dolgok, amik
időt vehetnek el így szumma szummárum beolvassuk
amit be kell olvasni !)
Tehát dolgunk "csekély" a FAT-ból ki kell találni mely sávokon nincs
egyáltalán használt szektor – cluster, s ezen üres sávok kivételével kell
minden mást beolvani.
Lássuk az elvi magvalósítás lépcsőfokait:
-
Hogy egyáltalán legyen miből megállapítani,
hogy mit kell s mit nem kell beolvasni, olvassuk be a lemezterületet a
bootsector-tól egészen a datastart-ig. (Bootsector, 1st
FAT, 2nd FAT, Rootentrys)
-
Ezekre úgy is szükség lesz az image-file-hoz,
így mentsük is le az image-file-ba ezt az első 33 szektort.
-
Ezek után egy második ciklusban mely a rootentry (a
főkönyvtár szektorai) utáni sávtól a maximum sávig megy történik
meg a beolvasás.
Ennek lépései:
-
Mielőtt eme ciklusba belépnénk tároljuk
el egy boolean tömbbe, hogy melyik cluster használt, s melyik nem. Erre
azért van szükség, mert FAT12-t használ az FDD és nem akarjuk a program
futása alatt a memóriában tartani az egész FAT-ot, hanem csak egy tömböt
ami azt tárolja, hogy van –e az x. cluster használva, vagy sem.
-
Nos ezek után beléphetünk második főbb ciklusunkba.
-
Ez a ciklus mielőtt meghívná a fizikai olvasást
megnézi, hogy a beolvasandó sávon lévő összes cluster üres –e. Sok aprólékos
konverziós dolog után nem kell mást tennie, mint azt a boolean tömböt megvizsgálnia
amit előbb feltöltöttünk a FAT-nak megfelelően. A vizsgálat tárgya, hogy
a sávon található mind a 18 szektor – cluster (most egyenlőek méretüket
tekintve az 1 sec / cluster miatt) üres –e. Ezt úgy készítsük el, hogy
mind a 18 cluster-nek megfelelő boolean tömb megfelelő elemeit össze vagyoljuk
(OR). Így ha egy igaz akkor már az
egész igaz, s be kell olvasni. Ez így leírva egész egyszerű de a megvalósítása
– melyet nem kívánok közölni – jelentősen rágósabb.
-
Persze ne felejtkezzünk el arról se ha nem
sikerült beolvasni előszörre egy sávot akkor azt próbáljuk meg még
párszor.
-
Ha meg a fentiek szerint kiderült, hogy nem kell beolvasni egy adott sávot,
mert teljesen üres, akkor egy olyan tömböt írjunk ki az imge-file-ba mely
üres, s nem tartalmaz semmit, pontosabban a DOS által szabványosnak tekinthető
$F6 hexa értéket.
FillChar(Buf^, SizeOf(Buf^), $F6);
-
Ha igazán igényesek vagyunk persze nem közvetlenül az Image-file-ba dolgozunk,
hanem egy cache-be. Persze 1.44 MB-os MEMÓRIA cache-t nehéz valós módban
készíteni DE használjunk XMS-t ! S ha vége az egész image-file készítésnek
ezután írjuk ki az XMSStream tartalmát file.
-
Továbbá ajánlott az image-file kezelő rutinnak
paraméterbe megadni olyan far rutinokat melyek pl. a 100%
kiírását végzik, vagy hibalekezelést valósítanak meg.
Mindezek után lássuk az általam megvalósított rutin kezelését:
function SaveDisk(PhisicalDrive: Byte; ToFile: String; RefreshProc:
PercentRefresher; ErrorProc: ErrorMessage; Use_XMS: XMSInfo): Boolean;
-
Első paraméternek a fizikai drive-számot adjuk
meg: 0 = A, 1 = B.
Figyelem: még egyszer elmondom,
hogy csak a 3.5” 1.44 MB és 1 sec / cluster lemezeket szereti ! Továbbá
szíveskedjünk NEM winchesterre használni, mert nem egészséges !
-
Második paraméter az image-file neve, amibe a floppy lemez image-t akarjuk
menteni.
-
Harmadik paraméter egy:
PercentRefresher = procedure(Percent: Byte);
Ilyen formán felépített rutin melyet far-nak definiálva hozunk
létre, s ez a rutin fogja paraméterként megkapni az aktuális %-ot, hogy
hol tart a rutin a másolásban.
-
ErrorMessage = procedure(Error : Byte);
Ez a rutin akkor hívódik meg ha hiba történt, s a hiba kódja az INT
13h-által generált hibakód.
-
Az utolsó paraméter meg csak arra szolgál,
hogy visszaadja a főprogramnak, hogy a SaveDisk() rutin használ –e XMS-t.
(Nem rossz mi ? Egy kis XMS kezelés, sux.)
XMSInfo = procedure(Use : Boolean);
-
A SaveDisk() függvény visszatérési értéke egy Boolean típus mely jelzi,
hogy sikerült –e az image-file-t elkészíteni.
Lássunk erre egy példaprogramot:
uses MakeIMG, Crt, DOS;
procedure WritePercent(Percent: Byte); far;
begin
GotoXY(1, 1);
Writeln(Percent, ' % readed');
end;
procedure Error(Err: Byte); far;
begin
GotoXY(1, 2);
if Err = $15 then Writeln('Drive Not Ready')
else begin
Writeln('Error: ', Err);
end;
WriteLn('Press any key to continue . . .');
ReadKey;
end;
procedure IsXMS(UseXMS: Boolean); far;
begin
GotoXY(1, 3);
Writeln('Use XMS: ', UseXMS);
end;
BEGIN
SaveDisk(0, ParamStr(1), WritePercent, Error, IsXMS);
{ Ez a 0 adja meg a fizikai drive-számot}
END.
Persze, ha ezt egy objektum-orientált felhasználó felületbe akarjuk
beilleszteni – mint ahogy én is tettem az R4s Quick Floppy programomban
– akkor sajnos át kell hágnunk az OOP elméletét, mert a Pascal nem
engedi meg a far objektum metódusok használatát, s így végképp nem tudjuk
őket meghivatni a SaveDisk() külső rutinunkkal.
Simán az objektumból kilógó far rutint kell deklarálni, amit
az objektum egyik metódusában található SaveDisk()-nek adunk oda. Persze
ezek a rutinok állítanak egy view-ot (Pl. StaticText.SetText() ami a
%-ot írja ki.) ami újabb megfontolásokat igényel, hogy helyesen illesszük
ezeket össze, s így újra az OOP elméletének szükséges áthágását követjük
el.
FCB-s file-kezelés dióhéjban
Hogy miért dióhéjban ?
Mert már a MicroSoft szerint is ezer éve elavult, s józan programozók
nem igen használják. Persze nem azért mondom el, mert teljesen ütődött
vagyok, hanem ez az egyszerűbb kezelési mód s ezen keresztül könnyebb lesz
megérteni a handle-es file-kezelést. Na és az is lehet, hogy valaki arra
vetemedne, hogy spec. okok miatt ezt szeretné használni, hát tegye, egészségére.
(Pedig amikor még réges-rég írtam
eme saját file-kezelést, arra gondoltam az FCB-s file-kezelésnél, hogy
belűl a handle-s rutinokkal lesz megoldva, de azt’ mégsem.)
Csak pár FCB-s utasítást – metódust valósítunk meg ezek:
-
File megnyitása FCB-vel:
function OpenFileByFCB(var FCB: TFCB): Boolean; virtual;
-
FCB-vel megnyitott file lezárása:
function CloseFileByFCB(var FCB: TFCB): Boolean; virtual;
-
Szekvenciális olvasás FCB-vel megnyitott file-ból:
function SeqReadByFCB(var FCB: TFCB): Boolean; virtual;
Még rég tisztáztuk, hogy mit értünk FCB-n, azért most feleleveníteném:
FCB – File Control Block. Ezt még a DOS 1.0 használták, s a CP/M-ből
vették át. Ez egy információs rekord mely a megnyitandó – megnyitott file
jellemzőit hordozza.
PFCB = ^TFCB;
TFCB = record {for DOS 5.0+}
DriveNumber :
Byte;
FileName : TChar8
FileExt : TChar3
CurrBlockNum :
Word;
LogicalRecSize:
Word;
FileSize : Longint;
FileDate,
FileTime : Word;
SysFileEntry :
Byte;
Attribute : Byte;
ExtraInfo : Byte;
StartCluster :
Word;
SectorNumber :
Word;
DirEntrypSec :
Byte;
RecordInCurBlk:
Byte;
RndAccRecNum :
Longint;
{R4sFCBsPos
: Byte;}
end;
Lépkedjünk végig gyorsan mezőnként az FCB
rekordon:
-
A drive, amelyiken a file megtalálható. (Ugyanis DOS 1.0-ban noha könyvtárak
még nem voltak, de már több meghajtó létezett.
-
A File-név megadása,
-
s a file-kiterjesztésének megadása. FIGYELEM: a nem használt karaktereket
#32-vel (space-szel) kell feltölteni !
-
Az éppen aktuális blokk száma, ugyanis FCB-s
file-kezelésben a file-t 128 byte-os blokkokra osztjuk. Így a legnagyobb
kezelhető file kb. 8 MB. Ez persze érthető, hisz amikor a DOS 1.0-t használták
akkor még 10 MB winchester-ek voltak.
-
A logikai rekord hossza, mert blokkokban logikai rekordokkal dolgozunk.
(Persze a rekord mérete lehet = a blokk méretével.)
-
A file hossza, ezt először a dir-entry-ből
veszi
-
A file létrehozásának vagy utolsó módosításának dátuma
-
A file létrehozásának vagy utolsó módosításának ideje
-
Itt kezdődnek a kiterjesztett funkciók:
Az elfoglalt rendszer-file-tábla bejegyzések száma
-
A file attribútuma
-
ExtraInfo:
bit 7: Read-only attribútum a System File
Table-ből (SFT)
bit 6: Archive attribútum az SFT-ből
bit: 5-0: A szektor számának felső 6 bit-je.
Lásd: 13 !
-
Az első cluster ahol a file kezdődik
-
A szektor száma (az alsó 16 bit – lásd 11. Bit 5-0) ahol a file
könyvtárbejegyzése található
-
Megadja, hogy hányadik bejegyzés tartozik a file-hoz a könyvtárban, adott
13. meghatározott szektorban. (Ezzel vége is a kiterjesztett funkcióknak.)
-
Az aktuális blokk, melyik rekordjával kívánunk
műveletet végezni. 0-127-ig, hisz a blokkot kezelhetjük úgy is, hogy a
rekord mérete egy byte.
-
A véletlen hozzáférésű művelet végzéskor a
rekord száma Longint-ben.
File megnyitása FCB-vel:
-
Ehhez az FCB rekordban meg kell adnunk a drive-ot,
-
A file-nevét és kiterjesztését.
-
(Ha assembly-ben az eredeti DOS FCB-s utasításokkal
dolgoznánk akkor helyet kellene biztosítanunk a további mezőknek amit a
DOS töltene ki meghívás után.)
A saját file-kezelő objektumunk, a TR4sFileDOS,
FCB-s file-megnyitásának megvalósítása:
function TR4sFileDOS.OpenFileByFCB(var FCB: TFCB): Boolean;
var
TempB : Byte;
TempW, Sector : Word;
Found, End_It : Boolean;
TempSec, TempEntry: Word;
begin
Found:=False; End_It:=False;
for Sector:=CurDIR.Sector to BootInf.Total_Sector
do
begin
ReadLogicalSector(Longint(Sector));
for TempW:=0 to MaxEntryPerSec-1
do
begin
CopyBufToDirEntry(ASector, TempW,
AEntry); {copy the TempW-th entry }
if IsNULLEntry(AEntry) then
{from ASector to AEntry var.}
begin {exit if no more}
End_It:=True;
Break;
end;
if IsEntryASimpleFile(AEntry)
and (AEntry.FileName <> '')
and (AEntry.FileName[1]
<> #0) then
if (AEntry.FileName
= FCB.FileName) and (AEntry.Extension = FCB.FileExt)
then
begin Found:=True; TempSec:=Sector; TempEntry:=TempW; Break; end;
end; {Next TempW}
if Found or End_It then Break;
end; {Next Sector}
if Found then
begin
with FCB do
begin
FileSize:=AEntry.FileSize;
FileTime:=AEntry.Time;
FileDate:=AEntry.Date;
StartCluster:=AEntry.ClusterNumber;
Attribute:=AEntry.Attribute;
DirEntrypSec:=TempW;
SectorNumber:=TempSec;
end;
TempB:=GetFirstFreeFCBsPos;
if TempB <> 255 then begin
FCB.R4sFCBsPos:=TempB; FCBs[TempB]:=Addr(FCB) end
else Error:=R4sFDOS_TooManyOpenFiles;
end else OpenFileByFCB:=False;
end;
Hogyan is működik eme rutin:
-
Első lépésben létrehozunk egy ciklust mely
a file-t keresi.
FIGYELEM ez a rutin még a DOS 1.0-ra hagyatkozva,
NEM kezeli le azon töredezett könyvtárstruktúrákat, melyek manapság előfordulhatnak
DOS 5.0+ alatt. Hisz DOS 1.0-ban még csak főkönyvtár volt és mint tudjuk
a főkönyvtár egy összefüggő lemezterületen a FAT-ok után és a data start
előtt helyezkedik el. Nem véletlen, hogy az FCB szektor szintű adatokat
is tárol.
-
Tehát a DOS 2.00-ban bevezették a könyvtárakat, így az FCB szerepe is átértékelődött.
Már ekkor inkább a Unix-ból átvett file-handle-es file-kezelést tanácsolták,
de a kompatibilitás megőrzése végett benthagyták a DOS-ban úgy, hogy a
műveletek mindig az aktuális könyvtárra értelmezettek. (Eléggé
logikátlan, mert bent maradt a cluster-szerinti
file-kezelés nem is ezzel van a baj, hanem inkább a bent maradt FCB-s szektor
buherálással, nekem spec. nem szimpatikus én nem így oldottam volna meg
… Persze sok mással egyetemben, hisz az MS-DOS-nak sok hátulütője van ...
Csak az üzletpolitika ...)
Így lesz az, hogy az aktuális könyvtár logikai szektorában, ill. attól
kezdünk el keresgetni.
-
Beolvassuk a szektort,
-
És létrehozunk egy olyan ciklust mely a beolvasott szektorban található
könyvtárbejegyzéseket 0-tól azoknak maximális számáig (ált. 16, mert
512 byte-os szektorban ennyi fér el, hisz a könyvtárbejegyzés hossza 32
byte. 512 / 32 = 16 db) nézi meg, hogy az adott könyvtárbejegyzésben
megegyezik –e a név a megnyitni kívánttal.
-
A file utáni keresés addig folytatódik, míg nem találtuk meg,
vagy vége nincs a könyvtárbejegyzéseknek, az-az #0 kezdőbetűjű bejegyzést
nem találunk.
-
Ha megtaláltuk a megnyitandó file-t, az FCB
rekord mezőinek értéket adunk a könyvtárbejegyzésből, s az aktuális könyvtár
szektorját, ill. azt, hogy hányadik bejegyzés ez a könyvtárban.
-
Majd eltároljuk a TR4sFileDOS objektum privát
mezőjében egy Array[1..50] of PFCB-ben
a FCB címét, hogy tudjunk később dolgozni vele. (Elárulom, hogy
úgy se fogunk dolgozni vele, csak réges-rég arra gondoltam, hogyha esetleg
teljesen megírnám az FCB-s file-kezelést is, akkor így jobban meglehetne
írni, mint a DOS teszi ezt.)
Ezzel megvolnánk, lássuk az FCB-vel megnyitott file bezárását:
function TR4sFileDOS.CloseFileByFCB(var FCB: TFCB): Boolean;
begin
FCBs[FCB.R4sFCBsPos]:=nil;
FillChar(FCB, SizeOf(FCB), 0);
CloseFileByFCB:=True;
end;
-
A belső FCBs rekord adott mezőjében kitöröljük
az eltárolt címet,
-
Majd kinullázuk a FCB rekordot, s kilépünk.
Végezetül lássuk az FCB-vel történő szekvenciális
file-olvasást:
function TR4sFileDOS.SeqReadByFCB(var FCB: TFCB): Boolean;
var
Cluster, ReadCluster, TempW, ToCopy, i, ToX: Word;
W, W0, W1, W2, W3 : Word;
begin
if (FCB.CurrBlockNum * 128) + (FCB.LogicalRecSize
* FCB.RecordInCurBlk) < FCB.FileSize then
begin
ReadCluster:=FCB.StartCluster;
W0:=FCB.LogicalRecSize;
W1:=Word(FCB.RecordInCurBlk);
W2:=Word(BootInf.Byte_Sector);
W3:=Word(FCB.CurrBlockNum * 128);
ToX:=Word((Word((W0 * W1) div W2)) + W3);
for Cluster:=1 to ToX do
ReadCluster:=Convert12BitFATToWord(FAT, ReadCluster);
TempW:=ConvertClusterNumberToLogicalSector(ReadCluster);
if ReadLogicalSector(TempW) then
begin
if (FCB.LogicalRecSize mod
BootInf.Byte_Sector) <> 0 then
begin
W:=(FCB.LogicalRecSize
* FCB.RecordInCurBlk) mod BootInf.Byte_Sector;
MoveMemXByteToBuffer(DTA^,
Seg(ASector), Ofs(ASector)+W, FCB.LogicalRecSize);
end else
CopyASectorToDTA(ASector,
FCB.LogicalRecSize);
if FCB.RecordInCurBlk = 127
then begin
Inc(FCB.CurrBlockNum);
FCB.RecordInCurBlk:=0;
end
else Inc(FCB.RecordInCurBlk);
end else begin SeqReadByFCB:=False; Error:=R4sFDOS_DriveNotReady
end;
end else begin SeqReadByFCB:=False; Error:=R4sFDOS_EOF;
end;
end;
-
Ha nem akarunk a file vége után címezni – olvasni, akkor van mit olvasnunk,
if (FCB.CurrBlockNum * 128)
+ (FCB.LogicalRecSize * FCB.RecordInCurBlk) < FCB.FileSize then
-
Az FCB.StartCluster mezőben bent van, hogy
honnét (melyik cluster-től) kell elkezdeni az olvasást (ezt egyébként
a könyvtár-bejegyzésből vette).
-
A biztos számkonverziók miatt külön-külön Word()-ökbe helyezünk el mindent.
-
!!! ? Mivel a file
töredezett lehet nem elég azt kiszámítani, hogy most az x-edik cluster
a kezdő cluster, és mi a 23 blokkban vagyunk így 23*128 byte-nyit kell
előremenni a cluster-ben. 23*128 byte (mert 128 byte egy blokk
hossza) = 2944 byte ? Így 5.75 cluster-rel
kellene előrébb menni (feltéve egy
szektor / cluster). NOS: NEM lehet azt mondani, hogy StartCluster +
5 mert lehet, hogy töredezve van a file !!!!!!
-
Így szépen a FAT segítségével, ahogy azt PC-X
User.12 leírtam ugrálni kell egyik cluster-ről a másikra, s mikor a megfelelőre
elértünk akkor olvashatunk. Lássuk azért az ábrát az ismétlés kedvéért:
(aki teljesen lemaradt pótolja, mert e nélkül nehéz lesz, lásd: !OLDUSER\)
Nos kutyafuttában egye fene, elismételhetem:
-
Egy adott könyvtárban keresgetünk adott file után, most az XY.TXT után.
-
A fenti OpenFileByFCB() rutin megtalálja, megnyitja.
-
Olvasni akarunk belőle, méghozzá a 2345-dik
byte-tól.
-
Ekkor a kezdő cluster-re ugrik a FAT-ban,
ahol a következő cluster száma van ahol adat van. (A FAT x. indexe
mindig annak a következő cluster-nek a számát
tartalmazza, ahol a file következő része, cluster-nyi darabja található.)
Így most az FAT első cluster-edik indexén (itt:12. cluster) található számú
cluster-re (54. cluster) ugrik, ha innen kell olvasni az-az 512 és 1024
byte közötti pozíciókban akkor a SeqReadByFCB() innen olvas, ha nem addig
keresi a megfelelő cluster-t így ugrálva a FAT-ban, amíg esetünkben el
nem érkezik a 4. Clusterre, hisz ez tartalmazza a 2048-2560 byte-okat,
s nekünk 2345-től kell olvasni.
-
Nos ezt az ugrálást valósítja meg a for Cluster:=1 to ToX do ciklus.
-
A ToX-et kiszámoltuk úgy, hogy az (aktuális
blokk * 128 byte + rekordméret * rekordhossz) / 512 byte a szektor – cluster
méret. Így a ToX jelenti, hogy mennyi cluster-t kell a StartCluster-től
előre ugrálni. A Convert12BitFATToWord();
rutin jelenti, hogy a FAT12-ből konvertálja egy word-dé az indexedik pozíciójú
számot cluster-ré.
-
Majd ha végigugráltunk amíg kell, a cluster-számból kiszámoljuk hányadik
logikai szektort kell beolvasnunk. (ConvertClusterNumberToLogicalSector())
-
Beolvassuk a megfelelő szektort a ReadLogicalSector()
rutinnal,
-
Majd ha éppen nem a szektor elején
kezdődik rekord amit be kell olvasnunk akkor kiszámoljuk hányadik byte-jától
kell a DTA-ra másolni, hisz a beolvasott értéket a DTA-n kell visszaadni
!!! A kiszámolás az alábbiak szerint történik:
W:=(FCB.LogicalRecSize * FCB.RecordInCurBlk) mod BootInf.Byte_Sector;
MoveMemXByteToBuffer(DTA^, Seg(ASector), Ofs(ASector)+W, FCB.LogicalRecSize);
A MoveMemXByteToBuffer() valósítja meg a memória másolást.
-
Ha éppen a szektor elejétől kell a
DTA-ra másolni akkor egyszerűbben is megoldható ezen rutinnal:
CopyASectorToDTA(ASector, FCB.LogicalRecSize);
Ez éppen annyi byte-ot másol a DTA-ra, mint a logikai-rekord hossz.
-
Beállítjuk az file-ban az aktuális pozíciót,
-
Ha a 127. rekordban vagyunk akkor az aktuális rekord = lesz 0-val, s az
aktuális blokk-ot, növeljük eggyel,
-
Ha nem a 127. logikai rekordban vagyunk akkor elég csak a rekord számot
eggyel növelni.
-
Egyéb apróságok, ha nem sikerül beolvasni a szektort, akkor hibaüzenet,
ill. a legelső if else-je itt
van, ha a file vége után akartunk olvasni újfent hibaüzenet.
Nos ezzel ki is végeztük volna az FCB-s file-kezelést,
csak az alapkonvenciókat kívántam vázolni, s egy jobb alapot adni a file-hendle-ös
file-kezeléshez amit következő számunkban kezdek el. Ha valaki valahol
elakadt sikítson egy eMail-t a címemre!
Bérczi László