Programavimas

Norėdami sukurti žemo lygio duomenų bazę, naudokite „RandomAccessFile“

Kaip aš ieškojau „JavaWorld“šio mėnesio idėjų svetainė Žingsnis po žingsnio, Aptikau tik kelis straipsnius, apimančius žemo lygio prieigą prie failų. Nors aukšto lygio API, pvz., JDBC, suteikia mums lankstumo ir galios, reikalingos didelėms įmonių programoms, daugeliui mažesnių programų reikia paprastesnio ir elegantiškesnio sprendimo.

Šiame straipsnyje mes sukursime RandomAccessFile klasė, leidžianti mums saugoti ir atkurti įrašus. Šis „įrašų failas“ bus lygiavertis nuolatinei „hashtable“, leidžiantis raktinius objektus laikyti ir gauti iš failų saugyklos.

Failų ir įrašų gruntas

Prieš pereidami tiesiai į pavyzdį, pradėkime nuo pagrindinio pagrindo. Pirmiausia apibrėžsime keletą terminų, susijusių su bylomis ir įrašais, tada trumpai aptarsime klasę java.io.RandomAccessFile ir priklausomybė nuo platformos.

Terminologija

Šie apibrėžimai yra pritaikyti mūsų pavyzdžiui, o ne tradicinei duomenų bazės terminologijai.

Įrašyti - Susijusių duomenų rinkinys, saugomas byloje. Įrašą paprastai sudaro keli laukai, kiekvienas iš jų yra įvardytas ir surinktas informacijos elementas.

Raktas - įrašo identifikatorius. Raktai paprastai yra unikalūs.

Failas - Nuoseklus duomenų, saugomų tam tikroje stabilioje saugykloje, pavyzdžiui, kietajame diske, rinkimas.

Nesvarbi failo prieiga - Leidžia duomenis nuskaityti iš savavališkų failo vietų.

Failo žymeklis - Skaičius, užimantis kito baito, kurį reikia nuskaityti iš failo, poziciją.

Įrašo rodyklė - Įrašo rodyklė yra failo žymeklis, nurodantis vietą, kurioje prasideda konkretus įrašas.

Indeksas - Papildoma prieigos prie įrašų byloje byla; tai yra, jis žymi raktus įrašyti rodykles.

Krūva - Nenuoseklios ir kintamo dydžio įrašų eilės byla. Norint prasmingai pasiekti įrašus, reikia kaupti tam tikrą išorinį indeksavimą.

Atkaklumas - Nurodo objekto ar įrašo saugojimą tam tikrą laiką. Ši laiko trukmė paprastai yra ilgesnė nei vieno proceso trukmė, todėl objektai paprastai yra išliko bylose ar duomenų bazėse.

Klasės java.io.RandomAccessFile apžvalga

Klasė RandomAccessFile yra „Java“ būdas suteikti nereikšmingą prieigą prie failų. Klasė leidžia mums pereiti į tam tikrą failo vietą naudojant Ieškoti() metodas. Nustačius failo žymeklį, duomenis galima nuskaityti ir įrašyti į failą naudojant „DataInput“ ir „DataOutput“ sąsajos. Šios sąsajos leidžia mums skaityti ir rašyti duomenis nepriklausomai nuo platformos. Kiti patogūs metodai RandomAccessFile leiskite mums patikrinti ir nustatyti failo ilgį.

Nuo platformos priklausantys aspektai

Šiuolaikinės duomenų bazės laikomos disko įrenginiuose. Diskų įrenginio duomenys saugomi blokai, kurie pasiskirstę po visą takelius ir paviršių. Diskas ieškoti laiko ir sukimosi vėlavimas diktuoja, kaip duomenis galima efektyviausiai saugoti ir gauti. Tipiška duomenų bazių valdymo sistema, norėdama supaprastinti našumą, labai priklauso nuo disko atributų. Deja (arba, laimei, atsižvelgiant į jūsų susidomėjimą žemo lygio failų įvestimis / išvestimis!), Šie parametrai yra toli gražu nepasiekiami naudojant aukšto lygio failų API, pvz., java.io. Atsižvelgiant į šį faktą, mūsų pavyzdys neatsižvelgs į optimizavimą, kurį galėtų suteikti žinios apie disko parametrus.

„RecordsFile“ pavyzdžio kūrimas

Dabar mes pasirengę sukurti savo pavyzdį. Pirmiausia išdėstysiu keletą projektavimo reikalavimų ir tikslų, išspręsiu vienalaikės prieigos klausimus ir nurodysiu žemo lygio failo formatą. Prieš tęsdami diegimą, mes taip pat apžvelgsime pagrindines įrašų operacijas ir atitinkamus jų algoritmus.

Reikalavimai ir tikslai

Šiame pavyzdyje pagrindinis mūsų tikslas yra naudoti a RandomAccessFile pateikti įrašų duomenų saugojimo ir gavimo būdą. Mes susiesime tipo raktą Stygos su kiekvienu įrašu kaip priemonė jį unikaliai identifikuoti. Raktai bus apriboti maksimaliu ilgiu, nors įrašo duomenys nebus ribojami. Šiame pavyzdyje mūsų įrašus sudarys tik vienas laukas - dvejetainių duomenų „dėmė“. Failo kodas jokiu būdu nebandys interpretuoti įrašo duomenų.

Kaip antrą dizaino tikslą, pareikalausime, kad kūrimo metu nebūtų nustatytas fiksuojamas įrašų skaičius, kurį palaiko mūsų failas. Leisime failui augti ir mažėti, kai įterpiami ir pašalinami įrašai. Kadangi mūsų rodyklės ir įrašų duomenys bus saugomi tame pačiame faile, dėl šio apribojimo mes pridėsime papildomos logikos, kad dinamiškai padidintume indekso erdvę pertvarkydami įrašus.

Prieiga prie failo duomenų yra didesnėmis eilėmis lėčiau nei prieiga prie atminties duomenų. Tai reiškia, kad failų, kuriuos pasiekia duomenų bazė, skaičius bus lemiamas našumo faktorius. Reikėsime, kad pagrindinės mūsų duomenų bazės operacijos nepriklausytų nuo failo įrašų skaičiaus. Kitaip tariant, jie bus pastovaus užsakymo laiko bylų prieigų atžvilgiu.

Kaip paskutinį reikalavimą laikysime, kad mūsų indeksas yra pakankamai mažas, kad jį būtų galima įkelti į atmintį. Tai palengvins mūsų įgyvendinimą reikalavimą, nurodantį prieigos laiką. Indeksą atspindėsime a „Hashtable“, kuris teikia tiesiogines įrašų antraščių paieškas.

Kodo taisymas

Šio straipsnio kode yra klaida, dėl kurios jis daugeliu atvejų gali sukelti „NullPointerException“. Abstrakčioje klasėje „BaseRecordsFile“ yra rutina, pavadinta „insureIndexSpace (int)“. Kodas skirtas perkelti esamus įrašus į failo pabaigą, jei reikia išplėsti indekso sritį. Kai „pirmojo“ įrašo talpa bus atstatyta į tikrąjį dydį, jis bus perkeltas į pabaigą. Tada „dataStartPtr“ nustatoma nukreipti į antrą failo įrašą. Deja, jei pirmajame įraše buvo laisvos vietos, naujasis dataStartPtr nenurodys galiojančio įrašo, nes jį padidino pirmojo įrašo ilgio o ne jo talpa. Modifikuotą „Java“ šaltinį, skirtą „BaseRecordsFile“, galite rasti šaltiniuose.

iš Rono Walkupo

Vyresnysis programinės įrangos inžinierius

„bioMerieux, Inc.“

Sinchronizavimas ir lygiagreti prieiga prie failo

Kad būtų paprasčiau, pirmiausia remiame tik vienos gijos modelį, kuriame failų užklausos draudžiamos vienu metu. Tai galime pasiekti sinchronizuodami viešosios prieigos metodus „BaseRecordsFile“ ir RecordsFile klasės. Atminkite, kad galite sušvelninti šį apribojimą, kad pridėtumėte palaikymą tuo pačiu metu skaitant ir rašant nekonfliktiškuose įrašuose: turėsite tvarkyti užrakintų įrašų sąrašą ir sutraukti skaitymus ir rašymus, jei norite tuo pačiu metu pateikti užklausas.

Išsami failo formato informacija

Dabar mes aiškiai apibrėžsime įrašų failo formatą. Failą sudaro trys regionai, kiekvienas jų turi savo formatą.

Failų antraščių regionas. Šiame pirmajame regione yra dvi pagrindinės antraštės, reikalingos norint pasiekti mūsų failo įrašus. Pirmoji antraštė, vadinama duomenų pradžios rodyklė, yra ilgas tai rodo įrašo duomenų pradžią. Ši vertė nurodo indekso regiono dydį. Antroji antraštė, vadinama įrašų antraštė, yra tarpt tai nurodo įrašų skaičių duomenų bazėje. Antraštių regionas prasideda nuo pirmo failo baito ir tęsiasi FILE_HEADERS_REGION_LENGTH baitų. Mes naudosimės readLong () ir readInt () skaityti antraštes ir writeLong () ir writeInt () parašyti antraštes.

Indekso regionas. Kiekvieną įrašą indekse sudaro raktas ir įrašo antraštė. Indeksas prasideda nuo pirmo baito po failo antraščių srities ir tęsiasi iki baito prieš duomenų pradžios žymeklį. Iš šios informacijos galime apskaičiuoti failo žymeklį į bet kurio iš jų pradžią n įrašai rodyklėje. Įrašų ilgis yra fiksuotas - pagrindiniai duomenys prasideda nuo pirmo baito indekso įraše ir tęsiasi MAX_KEY_LENGTH baitų. Atitinkama konkretaus rakto įrašo antraštė seka iškart po rakto rodyklėje. Įrašo antraštė nurodo, kur yra duomenys, kiek baitų gali būti įrašas ir kiek baitų jis iš tikrųjų yra. Rodyklės įrašai failų rodyklėje nėra ypatingos eilės ir neatitinka tvarkos, kuria įrašai saugomi faile.

Įrašyti duomenų regioną. Įrašo duomenų sritis prasideda nuo vietos, kurią nurodo duomenų pradžios žymeklis, ir tęsiasi iki failo pabaigos. Įrašai faile išdėstomi atgal ir atgal, tarp įrašų nėra laisvos vietos. Šią failo dalį sudaro neapdoroti duomenys be antraštės ar pagrindinės informacijos. Duomenų bazės failas baigiasi paskutiniame failo paskutinio įrašo bloke, todėl failo gale nėra papildomos vietos. Failas auga ir mažėja, kai įrašai pridedami ir ištrinami.

Įrašui priskirtas dydis ne visada atitinka faktinį įraše esančių duomenų kiekį. Įrašas gali būti laikomas konteineriu - jis gali būti pilnas tik iš dalies. Galiojantys įrašo duomenys išdėstomi įrašo pradžioje.

Palaikomos operacijos ir jų algoritmai

RecordsFile rems šias pagrindines operacijas:

  • Įterpti - prie failo pridedamas naujas įrašas

  • Skaityti - nuskaito įrašą iš failo

  • Atnaujinti - atnaujina įrašą

  • Ištrinti - ištrina įrašą

  • Užtikrinti pajėgumą - didinamas indekso regionas, kad būtų galima priimti naujus įrašus

Prieš pereidami prie šaltinio kodo, apžvelkime pasirinktus kiekvienos iš šių operacijų algoritmus:

Įdėti. Ši operacija į failą įterpia naują įrašą. Norėdami įterpti, mes:

  1. Įsitikinkite, kad įterpto rakto dar nėra faile
  2. Įsitikinkite, kad indekso sritis yra pakankamai didelė papildomam įrašui įrašyti
  3. Faile raskite laisvos vietos įrašui laikyti
  4. Įrašykite įrašo duomenis į failą
  5. Įtraukite įrašo antraštę į indeksą

Perskaityk. Ši operacija nuskaito prašomą įrašą iš failo pagal raktą. Norėdami gauti įrašą, mes:

  1. Norėdami indeksuoti nurodytą raktą prie įrašo antraštės, naudokite indeksą
  2. Ieškokite iki duomenų pradžios (naudodami žymeklį antraštėje saugomiems įrašo duomenims)
  3. Perskaitykite įrašo duomenis iš bylos

Atnaujinti. Ši operacija atnaujina esamą įrašą naujais duomenimis, naujus duomenis pakeisdama senais. Mūsų naujinimo veiksmai skiriasi, atsižvelgiant į naujų įrašų duomenų dydį. Jei nauji duomenys telpa į esamą įrašą, mes:

  1. Įrašykite įrašo duomenis į failą, perrašydami ankstesnius duomenis
  2. Atnaujinkite atributą, kuriame įrašo antraštėje yra duomenų ilgis

Priešingu atveju, jei duomenys yra per dideli įrašui, mes:

  1. Atlikite esamo įrašo ištrynimo operaciją
  2. Atlikite naujų duomenų įterpimą

Ištrinti. Ši operacija pašalina įrašą iš failo. Norėdami ištrinti įrašą, mes:

  1. Susigrąžinkite įrašui skirtą vietą pašalindami arba sutraukdami failą, jei įrašas yra paskutinis, arba pridėdami jo vietą prie gretimo įrašo

  2. Pašalinkite įrašo antraštę iš indekso pakeisdami ištrinamą įrašą paskutiniuoju indekso įrašu; tai užtikrina, kad rodyklė visada pilna, tarp įrašų nėra tuščių tarpų

Užtikrinkite pajėgumus. Ši operacija užtikrina, kad indekso sritis yra pakankamai didelė, kad joje tilptų papildomi įrašai. Cikle mes perkeliame įrašus iš failo priekio į galą, kol bus pakankamai vietos. Norėdami perkelti vieną įrašą, mes:

  1. Raskite failo pirmojo įrašo antraštę; atkreipkite dėmesį, kad tai yra įrašas, kurio duomenys yra įrašo duomenų regiono viršuje, o ne įrašas su pirmąja indekso antrašte

  2. Perskaitykite tikslinio įrašo duomenis

  3. Padidinkite failą pagal tikslinio įrašo duomenų dydį naudodami setLength (ilgas) metodas RandomAccessFile

  4. Parašykite įrašo duomenis failo apačioje

  5. Atnaujinkite perkelto įrašo duomenų rodyklę

  6. Atnaujinkite visuotinę antraštę, nurodančią pirmo įrašo duomenis

Išsami įgyvendinimo informacija - pereinama prie šaltinio kodo

Dabar esame pasirengę susitepti rankas ir išnagrinėti pavyzdžio kodą. Visą šaltinį galite atsisiųsti iš išteklių.

Pastaba: Norėdami sudaryti šaltinį, turite naudoti „Java 2“ platformą (anksčiau vadintą JDK 1.2).

„Class BaseRecordsFile“

„BaseRecordsFile“ yra abstrakti klasė ir yra pagrindinis mūsų pavyzdžio įgyvendinimas. Jis apibrėžia pagrindinius prieigos metodus, taip pat daugybę naudingų metodų, skirtų manipuliuoti įrašais ir indekso įrašais.