Tehtävät
Ensimmäisen osan oppimistavoitteet

Tuntee käsitteet digitalisaatio, tietokannanhallintajärjestelmä ja tietokanta. Ymmärtää tietokantojen roolin digitalisaatiossa. Tuntee ongelmia, joita tietokannanhallintajärjestelmät pyrkivät ratkaisemaan. Osaa luoda luokkakaavion annetun ohjelman lähdekoodista ja osaa luoda annetussa luokkakaaviossa kuvatut luokat. Ymmärtää luokkien, olioiden ja reaalimaailman käsitteiden suhteen. Osaa käsitellä tietoa ohjelmallisesti.

Kurssin alkukysely

Kurssiin kuuluu alkukysely. Käy vastaamassa kyselyyn alla olevassa osoitteessa.

Johdanto

Olemme tietoisesti ja tiedostamattomasti kytköksissä lukemattomiin järjestelmiin. Kodin sähkön- ja vedenkulutusta seurataan elektronisesti, lehti- ja palvelutilaukset tehdään digitaalisiin järjestelmiin, säätiedot tulevat automaattisesti mobiililaitteeseen, suurin osa perinteisestä kirjeillä tehdystä kommunikaatiosta tapahtuu sähköpostitse tai pikaviestinten kautta, kaupat seuraavat varastosaldojen kehitystä automaattisesti ostosten perusteella, sairaaloilla on sähköiset potilasrekisterit, yritykset tarjoavat räätälöityjä palveluita digitaalisen käyttäytymisen perusteella, ja niin edelleen. Toisaalta, vain muutamia vuosikymmeniä sitten, internet oli vain harvojen hupi, digitaaliset palvelut olivat harvinaisia, ja lähes kenelläkään ei esimerkiksi ollut henkilökohtaista kännykkää. Pankkikortit, joita kännyköillä tai muilla laitteilla tapahtuvat maksut ovat hiljalleen korvaamassa, ovat nekin olleet käytössä vain muutamia vuosikymmeniä.

Lähes jokainen edellämainituista palveluista perustuu tavalla tai toisella tiedon keräämiseen. Sähkön- ja vedenkulutuksesta jää historia, jota käytetään laskutuksessa sekä kulutuksen ennustamisessa. Lehti- ja palvelitilaukset tallennetaan järjestelmiin, joiden kautta voidaan suositella vastaavia sopivia tuotteita. Sähköpostit ja pikaviestinviestit säilyvät tyypillisesti ainakin lähettäjällä ja vastaanottajalla, jonka lisäksi esimerkiksi pikaviestinpalveluita tarjoava operaattori voi tallentaa viestit omalle palvelimelleen mahdollista tulevaa käyttöä varten. Kauppojen varastosaldojen kehityksen perusteella voidaan optimoida sisäänostoa ja tätä kautta pienentää hävikkiä sekä toisaalta vähentää tavaroiden varastointiin menevää tilaa. Potilasrekisterit sisältävät mm. hoito- ja rokotehistorian, jolloin lääkärin on helpompi toimia yllättävissä tilanteissa.

Uusia palveluita kehitetään myös jatkuvasti. Alla olevalla videolla on kuvattuna yhdysvaltalaisen ruokajätin Tescon toimintaa Etelä-Koreassa. Tesco muutti ruokatoimijoiden pelikenttää luomalla digitaalisia ostosmahdollisuuksia mm. kaupunkien metroasemille. Tuotteiden tilaaminen ja maksaminen tapahtuu kännykällä, ja tuotteet toimitetaan tilaajan kotiin.

 

 

Tässä palveluiden siirtymisessä ja kehittymisessä sähköiseen muotoon on kyse digitalisaatiosta. Digitalisaatio on tietoteknisten menetelmien ja sähköisessä muodossa olevan tiedon hyödyntämistä ja kehittämistä yksilöiden, yhteisöjen, yritysten ja yhteiskunnan toiminnan edesauttamiseksi. Tämä sisältää mm. tiedon perusteella tapahtuvaa liiketoimintamallien ja asiakaspalvelukokemusten kehittämistä, työn automatisointia ja virtaviivaistamista sekä uusien innovaatioiden luomista ja yrityksen toiminnan parantamista. Digitalisaation ytimessä on kyky hallinnoida ja käsitellä suuria tietomääriä.

Vaikka moni palvelu kerää tietoa palveluiden käyttäjistä ja siirtää palveluitaan sähköiseen muotoon, ei käyttäjien tietojen kerääminen ole itseisarvo. Arvoa voi tuottaa käyttäjille sekä yritykselle myös muilla tavoilla. Alla olevalla videolla on esimerkki eräästä IKEAn tuotteesta: IKEA on digitoinut (eli siirtänyt sähköiseen muotoon) tuotteiden tietoja sekä tehnyt tuotteistaan kolmiulotteisia malleja, jolloin niiden tuonti osaksi sovelluksia on suoraviivaista. Alla kuvattu tuote tarjoaa käyttäjille mahdollisuuden tarkastella miltä IKEAn tuote näyttäisi kotona.

 

 

Tällä kurssilla keskitytään suurien tietomäärien tallentamiseen keskittyneisiin palveluihin, joilla on paljon yhtäaikaisia käyttäjiä. Keskiössä ovat erityisesti relaatiotietokannat. Puhekielessä termillä tietokanta tarkoitetaan yleisesti ottaen tiedon tallentamiseen tarkoitettua paikkaa, josta tietoa voi myös hakea. Esimerkiksi kirkonkirjat voidaan nähdä eräänlaisena sukujen historiaa dokumentoivana tietokantana, jonka kautta sukututkija pääsee käsiksi sukunsa historiaan. Vaikka tietokannat ovat digitalisaation myötä siirtymässä paperisesta muodosta sähköiseen muotoon, on niiden tavoite pysynyt pitkälti samana: haluamme säilöä tietoa ja haluamme päästä tähän tietoon käsiksi.

Tietokannat ovat kaikkialla oleva (ubiikki) ilmiö. Tämä kurssimateriaali sijaitsee tietokannassa, kurssitehtäviin liittyvät pisteet kirjataan tietokantaan ja kurssin suoritusmerkintä kirjataan tietokantaan. Kännykässäsi on todennäköisesti kymmeniä erilaisia tietokantoja; yhteystiedot, kalenteri, herätyskello, aikavyöhykkeet, karttapalvelut, suosikkiverkkosivut, ym, joiden lisäksi moni kännykkäsovellus hyödyntää yhtä tai useampaa tietokantaa. Tietokannat voivat olla paikallisia, eli ne voivat sijaita samalla koneella tietokantaa käyttävän ohjelmiston kanssa, esimerkiksi kännykässä, tai ne voivat sijaita erillisellä palvelimella, johon otetaan tarvittaessa yhteyttä. Loppukäyttäjän näkökulmasta tietokannan konkreettisella sijainnilla ei ole juurikaan merkitystä, sillä haetun tiedon näkee tyypillisesti käytössä olevan sovelluksen käyttöliittymän kautta.

Tutustu tietokantaan!

Tässä kohtaa on hyvä hetki käydä tutustumassa muutamaan tietokantapalveluun. Osoitteessa http://hiski.genealogia.fi/hiski/ on Suomen Sukututkimusseuran ylläpitämä Historiakirjojen hakupalvelu. Käy sivulle, valitse kieli, etsi "Kaikista", ja valitse "Kastetut".

Minkälaisia tuloksia löydät omalla etunimelläsi? Entä, minkälaisia tuloksia löydät nimillä Matti ja Maija? Palvelu pyrkii muunmuassa sisällyttämään läheiset nimien muunnokset hakutuloksiin, sillä nimet muuttuvat ajan myötä.

Tiedon tallentamiseen ja hakemiseen liittyviä haasteita

Tiedon tallentamisessa sekä tiedon hakemisessa on muutamia ydinkysymyksiä ja ongelmakohtia. Nämä ovat seuraavia.

  • Tietoturva. Keillä on pääsy tietoon? Onko käyttäjillä erilaisia oikeuksia ja onko tiedon kirjoittaminen rajattu vain tietyille käyttäjäryhmille? Minne tieto tallennetaan fyysisesti -- onko sijainti Suomessa vai jossain muualla? Miten yhteys tietokantaan suojataan? ...
  • Suorituskyky. Miten tiedon hakeminen toteutetaan tehokkaasti? Entä jos käyttäjiä on samanaikaisesti satoja tai tuhansia?
  • Eheys. Miten säilyttää tiedon eheys, eli miten varmistaa, että tallennettu tietoa noudattaa (joitakin) annettuja sääntöjä? Miten varmistetaan, että tietyllä arvoalueella olevat arvot (esim. syntymävuosi) tallennetaan ja luetaan numerona? Miten kytköksissä olevaa tietoa tulee käsitellä -- jos henkilön äiti poistetaan tietokannasta, tuleeko myös henkilö poistaa? Miten varmistaa, että käyttäjä ei saa koskaan "vaillinaista" tietoa (esim. tiedon hakeminen kesken tiedon poistamisen)?
  • Pysyvyys. Miten tiedon tallentaminen toteutetaan siten, että järjestelmän toimintavirheet (esim. sähkökatkos) eivät johda tiedon katoamiseen?

Nykyaikaiset tietokannanhallintajärjestelmät tarjoavat ratkaisuja edellisiin ongelmiin.

Tietokannanhallintajärjestelmä

Tietokannahallintajärjestelmä on sovellus, jonka kautta käyttäjä voi luoda ja ylläpitää tietokantoja. Tietokannanhallintajärjestelmän vastuulla on tietokantaan kohdistuvien haku-, muokkaus- ja lisäystoimintojen lisäksi käyttöoikeuksien valvominen. Tietokannanhallintajärjestelmän vastuulla on myös tiedon eheyteen liittyvien sääntöjen noudattamisen valvonta. Tietokannassa voi olla esimerkiksi sääntö "Opiskelijan syntymävuoden tulee sisältää neljä numeroa", jolloin uusien opiskelijoiden lisääminen ilman oikein määriteltyä syntymävuotta ei onnistu. Vastaavia sääntöjä voidaan lisätä muunmuassa varausjärjestelmiin, esimerkiksi lentokoneiden paikkavarausjärjestelmissä halutaan varmistaa, että jokaisella istuimella on korkeintaan yksi varaus. Tietokannanhallintajärjestelmän vastuulla on myös varmistaa, ettei tietoa tuhoudu, vaikka tietokantaa käyttävä järjestelmä hajoaisi -- erilaiset varmuuskopiotoiminnallisuudet ovat tyypillisiä.

Edellisten lisäksi tietokannanhallintajärjestelmät tarjoavat välineitä tiedon hakemiseen liittyvien toimintojen tehokkuuden tarkastelemiseen. Vaikka esimerkiksi opintojen seurantaan liittyvä järjestelmä sisältäisi tiedot kaikista Helsingin yliopiston opiskelijoista (n. 35000) sekä kaikista kurssisuorituksista (rutkasti), tulisi tietokantaan tehtävien kyselyjen toimia nopeasti. Edellä mainittu tietomäärä on esimerkiksi Amazon-verkkokaupan mittakaavassa hyvin pieni.

Yksittäinen sovellus voi myös käyttää useampaa tietokantaa, jotka sijaitsevat eri tietokannanhallintajärjestelmissä. Tyypillinen esimerkki tällaisesta sovelluksesta on analytiikkapalvelu, joka yhdistää eri palveluiden tallentamaa tietoa yhteenvetoraporttien luomiseksi. Yksittäisessä tietokannanhallintajärjestelmässä voi toisaalta sijaita useampia erilaisiin sovelluksiin ja käyttötarkoituksiin liittyviä tietokantoja, joita jokaista käyttää eri käyttäjät tai eri yritys.

Tietokanta

Tietokanta on kokoelma tiettyyn aihepiiriin liittyviä säilytettäviä tietoja. Tietokannan luominen liittyy jonkinlaisen organisaation, yrityksen tai muun yhteisön tarpeeseen säilöä ja hakea tietoa. Esimerkiksi, yliopisto haluaa pitää kirjaa opiskelijoistaan ja heidän opintomenestystään, hotelli haluaa pitää kirjaa hotellin huoneiden varauksista ja kauppaketju haluaa pitää kirjaa asiakkaistaan ja asiakkaiden ostoksista.

Tallennettava tieto liittyy tyypillisesti johonkin tavoitteeseen. Yliopisto haluaa seurata opintojen etenemistä muunmuassa valtionhallinnolle raportointia varten, huoneiden varaustilannetta seuraava hotelli haluaa tietää milloin huoneita on paljon tarjolla ja milloin huoneet ovat lopussa. Kauppaketjun ensisijaisena tavoitteena lienee asiakkaiden ostosten seuranta myynnin optimoimiseksi.

Tietokantojen rakennetta ja jäsentelyä suunniteltaessa ongelmaa lähestytään tunnistamalla ongelma-alueen oleelliset käsitteet. Käsitteitä tarkastelemalla tunnistetaan mikä osa tiedosta on epäoleellista ja mikä osa tulee säilöä. Käsitteiden tunnistamisen yhteydessä selvitetään käsitteiden ominaisuuksia sekä niiden yhteyksiä. Esimerkiksi opiskelijan opintomenestyksen seurannassa oleellisia ovat ainakin käsitteet Opiskelija ja Kurssisuoritus, joilla on yhteys: opiskelijalla on kurssisuorituksia.

Tiedon kuvaamisesta

Tällä kurssilla tiedon kuvaamiseen käytetään UML-kieltä. Käytämme luokkakaavioita käsitteiden ominaisuuksien ja yhteyksien mallintamiseen ja sekvenssikaavioita järjestelmien välisen kommunikoinnin mallintamiseen. Koko UML-spesifikaatio ei kuitenkaan ole tässä oleellinen -- luokkakaavioistakin esimerkiksi kooste- ja kompositiomerkintä ei ole tällä kurssilla tarpeen.

Luokkakaavio, jossa on luokat Opiskelija ja Kurssisuoritus. Opiskelijalla on monta (nollasta äärettömään kurssisuoritusta). Jokaiseen kurssisuoritukseen liittyy yksi opiskelija.

Johdatus tiedon käsittelyyn Java-ohjelmoijalle

Java-ohjelmoijalle tietokantaan tallennetuilla käsitteillä ja niiden yhteyksillä on suorat vertauskuvat. Käsitteet ovat luokkia -- käsitteisiin liittyy ominaisuuksia eli attribuutteja (tai oliomuuttujia) -- ja käsitteiden yhteydet ovat viitteitä luokkien välillä. Edellä kuvatussa luokkakaaviossa olleet käsitteet Opiskelija ja Kurssisuoritus sekä yhteys opiskelijalla on kurssisuorituksia (ja kurssisuoritukseen liittyy yksi opiskelija) voidaan mallintaa Java-luokkina seuraavalla tavalla.

import java.util.ArrayList;
import java.util.List;

public class Opiskelija {
    List<Kurssisuoritus> kurssisuoritukset;
    String opiskelijanumero;
    String nimi;
  
    // muut attribuutit

    public Opiskelija(String opiskelijanumero, String nimi) {
        this.opiskelijanumero = opiskelijanumero;
        this.nimi = nimi;
        this.kurssisuoritukset = new ArrayList<>();
    }

    @Override
    public String toString() {
        return this.opiskelijanumero + "\t" + this.nimi;
    }
}
import java.util.Date;
  
public class Kurssisuoritus {
    Opiskelija opiskelija;
    String kurssi;

    // muut attribuutit
}

Edellisissä esimerkeissä oliomuuttujien näkyvyysmääreet sekä metodit ja konstruktorit on jätetty merkitsemättä. Huomaa, että luokkien väliset yhteydet eivät näy luokkakaaviossa, mutta luokat sisältävät niitä kuvaavat oliomuuttujat. Esimerkiksi yllä olevassa lähdekoodissa Kurssisuoritus sisältää tiedon opiskelijasta, mutta luokkakaaviossa opiskelija ei ole kurssisuorituksen oliomuuttuja.

Tehtävässä ei ole automaattisia testejä. Palauta tehtävä kun se täyttää tehtävän vaatimukset.

Alla on kuvattuna erään kirjojen lainausjärjestelmän luokkakaavio. Luo tehtäväpohjaan luokkakaavion esittämät luokat ja lisää luokkiin tarvittavat oliomuuttujat.

[Kirja|nimi:String;kirjoittaja:String;julkaisuvuosi:Integer]
						 [Hylly|sijainti:String]
						 [Nide|tunnus:Integer]
						 [Henkilo|nimi:String]
						 [Laina|alku:Date;loppu:Date;palautettu:Boolean]
						 [Nide]*-1[Hylly]
						 [Kirja]1-*[Nide]
						 [Laina]*-1[Henkilo]
						 [Nide]1-*[Laina]

Tiedon tallentaminen ja lataaminen

Tiedon tallentaminen pysyväismuistiin tarkoittaa käytännössä tiedon tallentamista kiintolevylle tai vastaavalle medialle. Tietokoneen käyttöjärjestelmä tarjoaa kiintolevyn käsittelylle abstraktion tiedosto -- tiedosto on käytännössä yksi tai useampi rajattu alue, johon tietoa on kirjoitettu. Tiedon tallennusmuoto määräytyy tallennettavan tiedon perusteella ja vaikuttaa sekä tallennusoperaatioiden että lukuoperaatioiden toteuttamiseen. Suoraviivainen tapa tallentaa tietoa on säilöä jokaisen käsitteen (luokan) ilmentymät (oliot) käsitekohtaisiin tiedostoihin, missä rivi kuvaa aina yksittäistä käsitettä.

Opiskelija- ja Kurssisuoritusoliot voidaan tallentaa tiedostoihin. Käytetään tiedostoja opiskelija.data ja kurssisuoritus.data -- tässä .data on itse keksimämme pääte.

Opiskelijalistan tallentaminen tiedostoon onnistuu nyt esimerkiksi seuraavasti.

// oletetaan, että käytössä on lista opiskelijoita
// List<Opiskelija> opiskelijat

PrintWriter pw = new PrintWriter("opiskelija.data");
opiskelijat.forEach(o -> pw.println(o.toString()));
pw.flush();
pw.close();

Vastaavasti opiskelijoiden lataaminen onnistuu seuraavasti.

// oletetaan, että käytössä on tyhjä opiskelijalista
// List<Opiskelija> opiskelijat

Files.lines(Paths.get("opiskelija.data")).forEach(rivi -> {
    String[] palat = rivi.split("\t");
    opiskelijat.add(new Opiskelija(palat[0], palat[1]));
});

Opiskelijan kurssisuoritukset eivät tässä tallennu opiskelijaa kuvaavaan tiedostoon. Koska kurssisuoritus on erillinen -- vaikkakin opiskelijaan liittyvä -- käsite, tallennetaan kurssisuoritukset erilliseen tiedostoon. Miten sitten saamme selville jokaiseen opiskelijaan kuuluvat kurssisuoritukset? Kun tallennamme kurssisuorituksia, tallennamme jokaiseen kurssisuoritukseen tiedon opiskelijasta, johon kurssisuoritus kuuluu. Joudumme tekemään oletuksen, että opiskelijanumero yksilöi opiskelijan.

// oletetaan, että käytössä on lista kurssisuorituksia
// List<Kurssisuoritus> kurssisuoritukset

PrintWriter pw = new PrintWriter("kurssisuoritus.data");
kurssisuoritukset.forEach(k -> pw.println(k.opiskelija.opiskelijanumero + "\t" + k.kurssi));
pw.flush();
pw.close();

Entä sitten kurssisuoritusten lataaminen? Kurssisuoritus-olio ei sisällä opiskelijanumeroa merkkijonona, joten kurssisuoritusten lataamisen yhteydessä tulee aiemmin ladatuista opiskelijoista aina etsiä opiskelijanumeroa vastaava olio.

Tehtävässä ei ole automaattisia testejä. Palauta tehtävä kun se täyttää tehtävän vaatimukset.

Tehtäväpohjassa on ohjelmakoodi opiskelijoiden lukemiseen ja tallentamiseen sekä kurssisuoritusten tallentamiseen. Täydennä ohjelmaa siten, että myös kurssisuoritusten lukeminen onnistuu -- kurssisuoritusten tulee sisältää viitteet opiskelijoihin.

Rajattu tiedon käsittely

Huom! Sisältöä päivitetty -- Edellinen esimerkki on tyypillinen ohjelmoinnin perusteiden ja jatkokurssin tiedon käsittelyesimerkki. Siinä on kuitenkin muutamia haasteita, sillä esimerkiksi pienten tietomäärien hakeminen isoista tiedostoista ei ole kovin tehokasta. Suurten tietomäärien ohjelmallisessa käsittelyssä hyödynnetään käyttöjärjestelmän tarjoamaa mahdollisuutta tiedoston osien lukemiseen. Ohjelmointikielet kuten Java tarjoavat tähän myös abstraktion -- Javalla luokka RandomAccessFile tarjoaa lukumahdollisuuden vain osaan tiedoston sisällöistä.

Edellä mainitun työvälineen avulla tiedostojen käsittely tapahtuu tavumuodossa. Jos tiedämme, että opiskelijan opiskelijanumeron pituus on 10 merkkiä, ja opiskelijanumero on tiedoston alussa, onnistuu lukeminen seuraavasti.

// Avataan tiedosto 'opiskelija.data' lukemista varten
RandomAccessFile tiedosto = new RandomAccessFile("opiskelija.data", "r");

// Varataan 10 tavua tilaa muistista opiskelijanumeroa varten
byte[] opnro = new byte[10];

// luetaan opnro-taulukkoon tiedoston alusta taulukon kokoinen määrä sisältöä
tiedosto.read(opnro);

// luodaan opiskelijanumerosta merkkijono
String opiskelijanumero = new String(opnro);

Vastaavasti, opiskelijanumeron vaihtaminen tiedoston tietyssä kohdassa onnistuu seuraavasti.

// Avataan tiedosto 'opiskelija.data' lukemista ja kirjoittamista varten
RandomAccessFile tiedosto = new RandomAccessFile("opiskelija.data", "rwd");

// Oletetaan, että käytössämme on opiskelijanumero "0123456789"
String opiskelijanumero = "0123456789";

// Etsitään kohta, mihin opiskelijanumero halutaan kirjoittaa -- kirjoitetaan alkuun
tiedosto.seek(0);

// Kirjoitetaan opiskelijanumero tiedostoon tietyn opiskelijan kohdalle.
tiedosto.write(opiskelijanumero.getBytes());

// Nyt opiskelijanumero tiedostossa on muuttunut.

Mitä hyötyä tästä on? Jos sovimme ennalta, että kunkin tiedostossa olevan kentän -- eli esimerkiksi opiskelijanumeron tai nimen -- pituus on määrätty, tiedämme ennalta opiskelijaolioiden sijainnit tiedostossa. Oletetaan, että opiskelijanumero on aina 10 merkkiä ja nimi 40 merkkiä. Tällöin uuden opiskelijan tiedot alkavat aina 50 merkin välein. Hyötynä tästä on muunmuassa se, että tällöin tietyn opiskelijan tietojen etsimisessä tiedostosta muistissa tulee olla korkeintaan vain 50 merkkiä -- alla esimerkki opiskelijan nimen etsimisestä tietyn opiskelijanumeron perusteella.

// Avataan tiedosto 'opiskelija.data' lukemista ja kirjoittamista varten
RandomAccessFile tiedosto = new RandomAccessFile("opiskelija.data", "rwd");

// Oletetaan, että haemme opiskelijanumeroa "0123456789"
String haettava = "0123456789";

byte[] opiskelijanumero = new byte[10];

for (int indeksi = 0; indeksi < tiedosto.length(); indeksi += 50) {
    // tälle ei käytännössä olisi tarvetta, sillä tiedoston kohta päivittyy
    tiedosto.seek(indeksi);

    // komento tiedosto.read lukee tiedostosta annetun tiedoston mittaisen määrän tietoa
    // tässä luettu määrä määräytyy opiskelijanumero-taulukon pituuden perusteella 
    tiedosto.read(opiskelijanumero);

    // lukemisen jälkeen tiedoston käsittelykohta siirtyy eteenpäin 10 merkillä

    // tehokkuusnäkökulmasta tässäkin todennäköisesti oikeasti verrattaisiin
    // yksittäisiä merkkejä
    if(!haettava.equals(new String(opiskelijanumero))) {
        continue;
    }

    // koska tiedoston käsittelykohta on siirtynyt eteenpäin 10 merkillä
    // on seuraavaksi luettavana nimi
    byte[] nimi = new byte[40];
    tiedosto.read(nimi);
    System.out.println("Haetun opiskelijan nimi on " + new String(nimi).trim());

    break;
}

Toisaalta, jos haluaisimme pitää kirjaa opiskelijoiden sijainneista, ja hyväksyä ajatus siitä, että opiskelijanumerot ovat jatkuvasti muistissa, voi opiskelijoiden sijainnit tallentaa hajautustaulukkoon.

// Avataan tiedosto 'opiskelija.data' lukemista ja kirjoittamista varten
RandomAccessFile tiedosto = new RandomAccessFile("opiskelija.data", "rwd");

// Oletetaan, että käytössä on hajautustaulukko, jossa
// on tieto opiskelijanumerosta tiedoston indeksiin
Map<String, Integer> opiskelijoidenSijainnit = new HashMap<>();

// Oletetaan, että haemme opiskelijanumeroa "0123456789"
String haettava = "0123456789";

// nyt opiskelijan nimen saa helpohkosti -- olettaen, että opiskelija on olemassa ja että
// hajautustaulussa on opiskelijan tiedot aloittava indeksi

// siirrytään tiedostossa sopivaan kohtaan -- opiskelijan nimi tulee opiskelijanumeron jälkeen
tiedosto.seek(opiskelijoidenSijainnit.get(haettava) + 10);

// luetaan nimi
byte[] nimi = new byte[40];
tiedosto.read(nimi);
System.out.println("Haetun opiskelijan nimi on " + new String(nimi).trim());

Tehtävässä ei ole automaattisia testejä. Palauta tehtävä kun se täyttää tehtävän vaatimukset.

Alla on kuvattuna erään viestijärjestelmän luokkakaavio. Jokaisella viestillä on sekä vastaanottaja että lähettäjä, jonka lisäksi viestiin kuuluu viestin sisältö. Käyttäjästä tallennetaan järjestelmään käyttäjätunnus, salasana, nimi, osoite ja puhelinnumero.

[Henkilo|kayttajatunnus:String;nimi:String;osoite:String;puhelinnumero:String]
					       [Viesti|sisalto:String]
					       [Henkilo]2-*[Viesti]

Oleta, että käyttäjätunnus on korkeintaan 8 merkkiä, nimi korkeintaan 30 merkkiä, osoite korkeintaan 30 merkkiä ja puhelinnumero korkeintaan 15 merkkiä. Oleta lisäksi, että viesti sisältää korkeintaan 255 merkkiä.

Kirjoita ohjelma, joka mahdollistaa henkilöiden lisäämisen ja muokkaamisen. Käytä tallennustoiminnallisuun toteuttamiseen luokkaa RandomAccessFile. Ohjelman suorituksen tulee olla seuraavanlainen -- alla olevassa esimerkissä punaisella merkityt kohdat ovat käyttäjän syöttämiä.

Valitse toiminto (1=lisää, 2=muokkaa, 3=listaa, 4=lopeta): 1
kayttajatunnus: arto
nimi: Arto
osoite: Kantakuja 4B
puhelinnumero: 012-3456789

Valitse toiminto (1=lisää, 2=muokkaa, 3=listaa, 4=lopeta): 1
kayttajatunnus: leena
nimi: Leena
osoite: Venetie 82
puhelinnumero: 123-4567890

Valitse toiminto (1=lisää, 2=muokkaa, 3=listaa, 4=lopeta): 3
arto, Arto, Kantakuja 4B, 012-3456789
leena, Leena, Venetie 82, 123-4567890

Valitse toiminto (1=lisää, 2=muokkaa, 3=listaa, 4=lopeta): 4

Kun ohjelmaan on tallennettu tiedot, tulee niiden löytyä ohjelmasta myös seuraavan suorituskerran yhteydessä. Tietojen muokkaustoiminnallisuus toimii siten, että ensin kysytään muokattavan käyttäjän käyttäjätunnusta. Tämän jälkeen ohjelma kysyy muokattavia tietoja yksi kerrallaan ja päivittää tiedot tiedostoon.

Valitse toiminto (1=lisää, 2=muokkaa, 3=listaa, 4=lopeta): 3
arto, Arto, Kantakuja 4B, 012-3456789
leena, Leena, Venetie 82, 123-4567890

Valitse toiminto (1=lisää, 2=muokkaa, 3=listaa, 4=lopeta): 2
tunnus: arto
nimi (Arto): Arto
osoite (Kantakuja 4B): Kantakuja 4B123
puhelinnumero (012-3456789): 022-3456789
    
Valitse toiminto (1=lisää, 2=muokkaa, 3=listaa, 4=lopeta): 3
arto, Arto, Kantakuja 4B123, 022-3456789
leena, Leena, Venetie 82, 123-4567890

Valitse toiminto (1=lisää, 2=muokkaa, 3=listaa, 4=lopeta): 4

Sisällysluettelo