Ohjelmointi

Käytä RandomAccessFile-tiedostoa matalan tason tietokannan rakentamiseen

Kun etsin JavaWorldtämän kuukauden ideoiden sivusto Askel askeleelta, Törmäsin vain muutamaan artikkeliin, jotka käsittelivät matalan tason tiedostojen käyttöä. Vaikka korkean tason sovellusliittymät, kuten JDBC, antavat meille suurten yrityssovellusten tarvitseman joustavuuden ja tehon, monet pienemmät sovellukset vaativat yksinkertaisemman ja tyylikkäämmän ratkaisun.

Tässä artikkelissa rakennamme laajennuksen RandomAccessFile luokka, jonka avulla voimme tallentaa ja noutaa tietueita. Tämä "tietuetiedosto" vastaa pysyvää hashtable-tiedostoa, jolloin avainkohteet voidaan tallentaa ja noutaa tiedostotallennuksesta.

Alusta tiedostoihin ja tietueisiin

Ennen kuin hyppäämme päinvastoin esimerkkiin, aloitetaan perustaustalla. Aloitamme määrittelemällä joitain termejä, jotka liittyvät tiedostoihin ja tietueisiin, sitten keskustelemme lyhyesti luokasta java.io.RandomAccessFile ja riippuvuus alustasta.

Terminologia

Seuraavat määritelmät on viritetty esimerkkimme sijaan perinteisen tietokantaterminologian sijaan.

Ennätys - Kokoelma asiaan liittyviä tietoja, jotka on tallennettu tiedostoon. Tietueella on tyypillisesti useita kentät, kukin on nimetty ja kirjoitettu tieto.

Avain - tietueen tunniste. Avaimet ovat yleensä ainutlaatuisia.

Tiedosto - Peräkkäinen tietojenkeruu jonkinlaiseen vakaan muistiin, kuten kiintolevylle.

Ei-välttämätön tiedostojen käyttö - Mahdollistaa tietojen lukemisen tiedoston mielivaltaisista sijainneista.

Tiedoston osoitin - Numero, joka pitää sisällään seuraavan tavun tiedostosta luettavan datan.

Tallenna osoitin - Tietueosoitin on tiedostoosoitin, joka osoittaa sijainnin, josta tietty tietue alkaa.

Indeksi - toissijainen tapa käyttää tiedostossa olevia tietueita; eli se kartoittaa avaimet tallentamaan osoittimia.

Pino - Järjestyksessä oleva tiedosto järjestämättömistä ja erikokoisista tietueista. Kasa vaatii jonkin verran ulkoista indeksointia, jotta tietueisiin pääsee mielekkäästi.

Sitkeys - Viittaa kohteen tai tietueen tallentamiseen tietyn ajan. Tämä aika on tyypillisesti pidempi kuin yhden prosessin jakso, joten objektit ovat yleensä jatkui tiedostoissa tai tietokannoissa.

Katsaus luokkaan java.io.RandomAccessFile

Luokka RandomAccessFile on Java-tapa tarjota epäoikeudenmukainen pääsy tiedostoihin. Luokan avulla voimme hypätä tiettyyn kohtaan tiedostossa käyttämällä etsiä () menetelmä. Kun tiedostosoitin on sijoitettu, tiedot voidaan lukea ja kirjoittaa tiedostoon Datan syöttö ja DataOutput rajapinnat. Näiden rajapintojen avulla voimme lukea ja kirjoittaa tietoja alustasta riippumattomalla tavalla. Muut kätevät menetelmät RandomAccessFile anna meidän tarkistaa ja asettaa tiedoston pituus.

Alustasta riippuvat näkökohdat

Nykyaikaiset tietokannat luottavat levyasemiin tallennukseen. Levyaseman tiedot tallennetaan lohkot, jotka on jaettu eri puolille kappaleita ja pinnoille. Levy etsiä aikaa ja pyörimisviive sanella, miten tietoja voidaan tallentaa ja hakea tehokkaimmin. Tyypillinen tietokannan hallintajärjestelmä riippuu läheisesti levyn ominaisuuksista suorituskyvyn virtaviivaistamiseksi. Valitettavasti (tai onneksi, riippuen kiinnostuksestasi matalan tason tiedosto I / O: han!), Nämä parametrit ovat kaukana ulottumattomista käytettäessä korkean tason tiedostojen sovellusliittymää, kuten java.io. Ottaen huomioon tämän tosiasian esimerkissämme jätetään huomiotta optimoinnit, joita levyn parametrien tuntemus voisi tarjota.

Suunnittelu RecordsFile-esimerkki

Nyt olemme valmiita suunnittelemaan esimerkkimme. Aloitan asettamalla joitain suunnitteluvaatimuksia ja tavoitteita, ratkaisemalla samanaikaisen käytön ongelmat ja määrittelemällä matalan tason tiedostomuodon. Ennen toteutuksen aloittamista tarkastelemme myös tärkeimmät tietueoperaatiot ja niitä vastaavat algoritmit.

Vaatimukset ja tavoitteet

Päätavoitteemme tässä esimerkissä on käyttää a RandomAccessFile tarjota tapa tallentaa ja hakea tietuetietoja. Yhdistämme tyypin avaimen Merkkijono kunkin tietueen avulla keino yksilöidä se. Avaimet rajoitetaan enimmäispituuteen, vaikka tietuetietoja ei rajoiteta. Tässä esimerkissä tietueemme koostuvat vain yhdestä kentästä - binääridatan "blobista". Tiedostokoodi ei yritä tulkita tietueen tietoja millään tavalla.

Toisena suunnittelutavoitteena vaadimme, että tiedostojemme tukemien tietueiden määrää ei vahvisteta luontihetkellä. Annamme tiedoston kasvaa ja kutistua, kun tietueita lisätään ja poistetaan. Koska hakemisto- ja tietuetietomme tallennetaan samaan tiedostoon, tämä rajoitus saa meidät lisäämään logiikkaa lisäämään hakemistotilaa dynaamisesti järjestelemällä tietueita.

Tiedoston tietojen käyttäminen on suuruusluokkaa hitaampaa kuin muistissa olevien tietojen käyttö. Tämä tarkoittaa, että tietokannan suorittamien tiedostojen lukumäärä on määräävä suorituskykykerroin. Vaadimme, että tietokannan päätoiminnot eivät riipu tiedostossa olevien tietueiden määrästä. Toisin sanoen ne ovat jatkuvan tilausajan tiedostojen käyttöoikeuksien osalta.

Viimeisenä edellytyksenä oletetaan, että hakemisto on riittävän pieni ladattavaksi muistiin. Tämä helpottaa toteutuksemme täyttämään vaatimuksen, joka määrää käyttöajan. Peilataan hakemisto a Hashtable, joka tarjoaa välittömät tietueotsikot.

Koodikorjaus

Tämän artikkelin koodissa on vika, joka saa sen ajamaan NullPointerExceptionin monissa mahdollisissa tapauksissa. Abstraktissa luokassa BaseRecordsFile on rutiini nimeltä insureIndexSpace (int). Koodin on tarkoitus siirtää olemassa olevat tietueet tiedoston loppuun, jos hakemistoaluetta on laajennettava. Kun "ensimmäisen" tietueen kapasiteetti on palautettu todelliseen kokoonsa, se siirretään loppuun. DataStartPtr asetetaan sitten osoittamaan tiedoston toiseen tietueeseen. Valitettavasti, jos ensimmäisessä tietueessa oli vapaata tilaa, uusi dataStartPtr ei osoita kelvollista tietuetta, koska sitä lisättiin ensimmäisen tietueen pituus sen kapasiteetin sijasta. Muokattu Java-lähde BaseRecordsFile-tiedostolle löytyy Resursseista.

Ron Walkupilta

vanhempi ohjelmistosuunnittelija

bioMerieux, Inc.

Synkronointi ja samanaikainen tiedostojen käyttö

Yksinkertaisuuden vuoksi aloitamme tukemalla vain yksisäikeistä mallia, jossa tiedostopyynnöt eivät saa tapahtua samanaikaisesti. Voimme saavuttaa tämän synkronoimalla BaseRecordsFile ja RecordsFile luokat. Huomaa, että voit lieventää tätä rajoitusta lisätäksesi tukea samanaikaisille lukemisille ja kirjoittamisille ristiriitaisissa tietueissa: Sinun on ylläpidettävä lukittujen tietueiden luetteloa ja lomitettava lukut ja kirjoitukset samanaikaisille pyynnöille.

Tiedot tiedostomuodosta

Määritämme nyt nimenomaisesti tietueiden muodon. Tiedosto koostuu kolmesta alueesta, joista jokaisella on oma muoto.

Tiedoston otsikkoalue. Tällä ensimmäisellä alueella on kaksi välttämätöntä otsikkoa, joita tarvitaan tiedostomme tietueiden käyttämiseen. Ensimmäinen otsikko, nimeltään tietojen aloitusosoitin, on pitkä joka osoittaa tietueen alkuun. Tämä arvo kertoo meille indeksialueen koon. Toinen otsikko, nimeltään num tietueiden otsikko, on int joka antaa tietokannan tietueiden määrän. Otsikkoalue alkaa tiedoston ensimmäisestä tavusta ja jatkuu FILE_HEADERS_REGION_LENGTH tavua. Käytämme readLong () ja readInt () lukemaan otsikot ja writeLong () ja writeInt () kirjoittaa otsikot.

Hakemistoalue. Jokainen hakemiston merkintä koostuu avaimesta ja tietueotsikosta. Hakemisto alkaa tiedostotunnisteiden alueen ensimmäisestä tavusta ja jatkuu tavuun ennen datan aloitusosoitinta. Näiden tietojen perusteella voimme laskea tiedoston osoittimen minkä tahansa n merkinnät hakemistoon. Merkinnöillä on kiinteä pituus - avaintiedot alkavat hakemistokohdan ensimmäisestä tavusta ja jatkuvat MAX_KEY_LENGTH tavua. Tietyn avaimen vastaava tietueotsikko seuraa heti hakemiston avainta. Tietueen otsikko kertoo meille, missä data sijaitsee, kuinka monta tavua tietueessa voi olla ja kuinka monta tavua sillä on. Tiedostohakemiston hakemistomerkinnät eivät ole tietyssä järjestyksessä, eivätkä ne vastaa sitä järjestystä, jossa tietueet tallennetaan tiedostoon.

Tallenna data-alue. Tietuedata-alue alkaa datan aloitusosoittimen osoittamasta sijainnista ja ulottuu tiedoston loppuun. Tietueet sijoitetaan taaksepäin tiedostoon siten, että tietueiden välillä ei ole vapaata tilaa. Tämä tiedoston osa koostuu raakatiedoista ilman otsikkoa tai avaintietoja. Tietokantatiedosto päättyy tiedoston viimeisen tietueen viimeiseen lohkoon, joten tiedoston lopussa ei ole ylimääräistä tilaa. Tiedosto kasvaa ja pienenee, kun tietueita lisätään ja poistetaan.

Tietueelle varattu koko ei aina vastaa tietueen todellista määrää. Levy voidaan ajatella kontiksi - se voi olla vain osittain täynnä. Voimassa olevat tietuetiedot sijoitetaan tietueen alkuun.

Tuetut toiminnot ja niiden algoritmit

RecordsFile tukee seuraavia päätoimintoja:

  • Lisää - Lisää uuden tietueen tiedostoon

  • Lue - Lukee tietueen tiedostosta

  • Päivitä - päivittää tietueen

  • Poista - poistaa tietueen

  • Varmista kapasiteetti - Kasvaa hakemistoaluetta uusien tietueiden sijoittamiseksi

Ennen kuin käymme läpi lähdekoodin, käymme läpi valitut algoritmit kullekin näistä toiminnoista:

Lisää. Tämä toiminto lisää uuden tietueen tiedostoon. Lisätäkseen me:

  1. Varmista, että lisättävä avain ei ole jo tiedostossa
  2. Varmista, että hakemistoalue on riittävän suuri lisämerkintää varten
  3. Löydä tiedostosta vapaata tilaa, joka on riittävän suuri tietueen pitämiseen
  4. Kirjoita tietueen tiedot tiedostoon
  5. Lisää tietueen otsikko hakemistoon

Lukea. Tämä toiminto noutaa pyydetyn tietueen tiedostosta avaimen perusteella. Voit hakea tietueen seuraavasti:

  1. Karttaa annettu avain hakemiston avulla tietueen otsikkoon
  2. Etsi tietojen alkuun (käytä osoitinta otsikkoon tallennettuihin tietoihin)
  3. Lue tietueen tiedot tiedostosta

Päivittää. Tämä toiminto päivittää olemassa olevan tietueen uusilla tiedoilla korvaamalla uudet tiedot vanhoilla. Päivityksen vaiheet vaihtelevat uuden tietuetiedon koon mukaan. Jos uudet tiedot sopivat olemassa olevaan tietueeseen,

  1. Kirjoita tietueen tiedot tiedostoon korvaamalla edelliset tiedot
  2. Päivitä tietueen pituuden sisältävä attribuutti tietueen otsikossa

Muussa tapauksessa, jos tiedot ovat liian suuria tietueelle, me:

  1. Suorita olemassa olevan tietueen poisto
  2. Lisää uudet tiedot

Poistaa. Tämä toiminto poistaa tietueen tiedostosta. Voit poistaa tietueen seuraavasti:

  1. Palauta poistettavalle tietueelle varattu tila joko kutistamalla tiedostoa, jos tietue on viimeinen tiedostossa, tai lisäämällä sen tila viereiseen tietueeseen

  2. Poista tietueen otsikko hakemistosta korvaamalla poistettava merkintä hakemiston viimeisellä merkinnällä. tämä varmistaa, että hakemisto on aina täynnä, eikä merkintöjen välillä ole tyhjiä välilyöntejä

Varmista kapasiteetti. Tämä toimenpide varmistaa, että hakemistoalue on riittävän suuri uusien merkintöjen vastaanottamiseksi. Silmukassa siirrämme tietueet tiedoston edestä loppuun, kunnes tilaa on riittävästi. Yhden tietueen siirtäminen:

  1. Etsi tiedoston ensimmäisen tietueen otsikko; Huomaa, että tämä on tietue, jonka tiedot ovat tietuealueen yläosassa - ei hakemiston ensimmäisen otsikon tietue

  2. Lue kohdetietueen tiedot

  3. Kasvata tiedostoa kohdetietueen koon mukaan käyttämällä setLength (pitkä) menetelmä RandomAccessFile

  4. Kirjoita tietueen tiedot tiedoston alaosaan

  5. Päivitä siirretty tietue datasäiliö

  6. Päivitä yleinen otsikko, joka osoittaa ensimmäisen tietueen tietoihin

Toteutustiedot - siirtyminen lähdekoodiin

Olemme nyt valmiita likaamaan kätemme ja selvittämään esimerkin koodin. Voit ladata koko lähteen Resursseista.

Huomaa: Lähteen kääntämiseen on käytettävä Java 2 -alustaa (aiemmin nimellä JDK 1.2).

Luokan BaseRecordsFile

BaseRecordsFile on abstrakti luokka ja on esimerkkimme päätoteutus. Se määrittelee tärkeimmät käyttömenetelmät sekä joukon apuvälineitä tietueiden ja hakemistomerkintöjen manipuloimiseksi.