Poglavje 2
Spoznavanje osnov jezika java

V tem poglavju bomo osnove jezika java spoznavali skozi posamezne preproste naloge. Spoznali bomo nekaj novih pojmov ter pokazali praktične primere uporabe. Pri tem se ne bomo spuščali v podrobnosti. Šele ko bomo v kasnejših poglavjih omenjene pojme podrobneje spoznali, jih bo bralec zares razumel, do tedaj pa bo lahko rešitve uporabljal kot gradnike pri reševanju drugih nalog (programerski recepti).

2.1 Prvi program

No, pa začnimo. Večina knjig o programskih jezikih začne s preprostim primerom - s programom, ki na zaslon izpiše pozdravno besedilo (to so tako imenovani HelloWorld programi), mi pa se bomo zadeve lotili malček drugače. Naš prvi program bo le malenkost bolj zapleten, a mnogo bolj uporaben (bralec lahko na koncu tega razdelka za vajo program HelloWorld napiše sam), saj bo izračunal in na zaslon izpisal bančne obresti na vezano vlogo. Zastavimo si prvo nalogo takole:

Naloga 2-I. Napiši program, ki izračuna in na zaslon izpiši stanje na bančnem računu po n letih, če vežemo G denarja po obrestni meri p procentov.  

Program bomo napisali v datoteki z imenom Obresti.java. Najprej bomo sestavili ogrodje, ki ga potrebuje vsak javanski program - razred.

 

public class Obresti { 
 
}

Naslednji korak je metoda main():

Za rešitev naloge 2-I bomo uporabili matematično formulo za obrestno-obrestni račun

          (     p  )n
Gn =  G *  1 + ----
               100

ki pravi, da je stanje po n letih enako n-ti potenci obrestne mere pomnoženi z glavnico. Za računanje potence bomo v programu uporabili metodo Math.pow().

Rešitev naloge 2-I.: Izpis stanja na računu Obresti.java

 

Pri pregledovanju zgornje rešitve naj bo bralec posebej pozoren na naslednje:

2.2 Večkratno ponavljanje ukazov (zanka)

Naslednji program bo predstavil koncept zanke. Za večkratni izpis istega besedila bomo namesto metode copy/paste v času pisanje programa uporabili t.i. zanko for. Program bo na ta način postal lepši (preglednejši) in hkrati preprostejši za vzdrževanje in popravljanje.

Naloga 2-II. Napiši program, ki petkrat izpiše besedilo ”Java je zakon!”.  

Z znanjem, ki smo ga osvojili do sedaj, lahko nalogo rešimo takole.

Rešitev naloge 2-II.: Večkratni izpis zanke/JavaZakon.java

 

Zgornja rešitev je sicer pravilna, vendar ima določene pomanjkljivosti. Če bi, na primer, naloga zahtevala 100-kratni izpis, bi koda postala zelo dolga, nepregledna in neobvladljiva (vsak morebitni popravek bi bilo treba vnesti 100-krat). Podobno kot python (in večina drugih jezikov) tudi programski jezik java ponuja orodja za reševanje tovrstnih problemov – zanke:

Če lahko neko nalogo rešimo z uporabo ene od zank, lahko isto nalogo rešimo tudi z uporabo katerekoli od drugih dveh zank. Izbira zanke je torej povsem prepuščena programerju. Čeprav so kriteriji za izbiro zanke zelo različni, si morda velja zapomniti naslednje navodilo: če v zanki potrebujem števec, potem uporabim zanko for, sicer uporabim zanko do ali while.

Nalogo 2-II lahko rešimo tako s pomočjo for

Rešitev naloge 2-II.: Večkratni izpis s for zanko zanke/JavaZakonFor.java

 

ali while zanke

Rešitev naloge 2-II.: Večkratni izpis z while zanko zanke/JavaZakonWhile.java

 

Zanka for števec nadzira samostojno, pri uporabi zanke while pa moramo sami paziti na:

2.3 Spremenljivke in njihovi tipi

Za shranjevanje podatkov v programih uporabljamo spremenljivke. Podatke, ki so shranjeni v njih, lahko med tekom programa spreminjamo (od tod izvira ime). V primerih iz prejšnjega poglavja smo uporabili spremenljivko z imenom i, s pomočjo katere smo “šteli” število ponovite zanke. Najprej smo v spremenljivko zapisali 1, nato smo pri vsakem izpisu njeno vrednost povečali (i=i+1 pomeni: i naj dobi vrednost i+1). Ko je spremenljivka i dosegla vrednost 5, smo nehali izpisovati.

Vsaka spremenljivka v javi ima svoje enolično določeno ime in tip. Tip določa, kakšne podatke bo spremenljivka hranila (cela števila, realna števila, znake, ...; za podrobnejše informacije o podatkovnih tipih glej poglavje ??). Pred prvo uporabo spremenljivke, moramo to deklarirati, kar pomeni, da moramo prevajalniku povedati, kako bo spremenljivki ime in kakšnega tipa bo. To storimo z ukazom

 

  tip_spremenljivke ime_spremenljivke;

kjer tip_spremenljivke in ime_spremenljivke predstavljata konkretni tip in ime spremenljivke, ki jo deklariramo. V zgornjem primeru smo potrebovali spremenljivko, ki hrani cela števila (1, 2, 3, ...), torej spremenljivko tipa int (okrajšava za integer, ki pomeni celo število). Spremenljivko smo poimenovali z i in deklarirali z

 

  int i;

Če želimo, lahko ob deklaraciji spremenljivko tudi inicializiramo (t.j. določimo začetno vrednost). V programu zanke/JavaZakonWhile.java smo to storili z

 

  int i = 1;

Pred inicializacijo vrednost spremenljivke ni znana (v spremenljivki je lahko zapisano karkoli). Predpostavka, da ima vsaka spremenljivka “na začetku” vrednost 0, je ena od pogostejših napak programerjev začetnikov. K sreči java preprečuje tovrstne začetniške napake – dokler spremenljivka ni inicializirana, je ne moremo uporabljati (prevajalnik nas na napako opozori, program se ne prevede).

2.4 Preprost formatiran izpis

Naloga 2-III. Popravi program zanke/JavaZakonFor.java tako, da bodo posamezne vrstice izpisa oštevilčene. Izpis naj ima naslednjo obliko:

1. Java je zakon! 
2. Java je zakon! 
3. Java je zakon! 
4. Java je zakon! 
5. Java je zakon!
 

Glede na dejstvo, da za nadziranje poteka zanke for uporabljamo števec, je rešitev naloge dokaj preprosta. Isti števec lahko uporabimo tudi pri izpisu. Vprašanje je samo, kako (s katero metodo) izpišemo “živo” besedilo (za razliko od besedila ”Java je zakon”, ki se ne spreminja, bo imel števec v vsaki iteraciji zanke drugo vrednost). Odgovor: “živo” besedilo izpisujemo z metodo printf.

Oglejmo si najprej preprost primer uporabe metode printf. Če želimo izpisati vsoto spremenljivk x z vrednostjo 7 in y z vrednostjo 5 v obliki  7 + 5 = 12, to storimo tako, kot prikazuje spodnji program.

Izpis vsote spremenljivk x in y osnove/VsotaXY.java

 

Metoda printf v programu VsotaXY.java vsa pojavljanja zaporedja znakov %d zamenja z vrednostmi spremenljivk x in y ter z vsoto x+y (glej sliko 2.1). Pri klicu metode printf s prvim parametrom določimo, kakšna bo oblika (format), drugi parametri pa določijo vsebino izpisa. Število parametrov pri klicu metode printf je odvisno od formata (število parametrov, ki sledijo prvemu, je enako številu znakov % v prvem parametru).


images/printf5712.eps


Slika 2.1: Formatiran izpis z uporabo metode printf


Rešitev naloge 2-III. Za rešitev naloge 2-III moramo spremeniti le peto vrstico programa JavaZakonFor.java, ki se zdaj pravilno glasi takole (glej program JavaZakonPlus.java):

  printf(”%d._Java_je_zakon\n”, i);

2.5 Malo zahtevnejši formatiran izpis

Naloga 2-IV. Napiši program, ki bo izpisal tabelo za pretvorbo prvih 32 naravnih števil med desetiškim, osmiškim in šestnajstiškim številskim sistemom. Začetek tabele naj bo takle:


Desetisko | Osmisko | Sestnajstisko 
      0   |     0   |           0 
      1   |     1   |           1 
      2   |     2   |           2 
      3   |     3   |           3 
      4   |     4   |           4 
      5   |     5   |           5 
      6   |     6   |           6 
      7   |     7   |           7 
      8   |    10   |           8 
      9   |    11   |           9 
     10   |    12   |           A

Slika 2.2: Tabela za pretvorbo med desetiškim, osmiškim in šestnajstiškim sistemom


 

Da bomo znali rešiti to nalogo, moramo spoznati še nekatere možnosti, ki jih ponuja metoda printf. Ta namreč poleg izpisa celega števila (z zaporedjem %d) med drugim omogoča tudi naslednje izpise:

realno število

%f

znak

%c

niz

%s

celo število v osmiškem sistemu

%o

celo število v šestnajstiškem

%X

 

Metodo printf uporabljamo tudi za poravnavo izpisa: zahtevamo lahko tak izpis podatkov, ki bo zasedel natančno določeno število mest (če je podatek prekratek, bo printf dodal presledke). Tako, na primer, s klicem metode

 

  printf("x=%5d", 10)

dosežemo naslednji izpis:

x=10

(pred številom 10 so izpisani trije presledki, saj smo z %5d zahtevali, naj izpis celega števila zasede 5 mest; ker število 10 zasede le dve mesti, metoda printf doda tri presledke).

Pri izpisu realnih števil lahko določimo tudi število števk za decimalno piko (primer: izpis števila na 3 decimalna mesta dosežemo z %.3f). Nekaj primerov uporabe metode printf prikazuje naslednji program.

Primeri izpisa s pomočjo metode printf osnove/Printf.java

 

Ko poženemo program Printf.java, se na zaslon izpiše

Znaki:aA 
Celastevila:2012123456789 
Presledkipredstevilom:2012 
Znak0predstevilom:0000002012 
Stev.sistemi:100641440x640144aA 
Realnastevila:3,14+3e+003.141600E+00 
Niz:Tojeniz

Rešitev naloge 2-IV. Za izpis 32 vrstic tabele uporabimo zanko for , v kateri števec i teče od 1 do 32. V posamezni iteraciji zanke izpišemo i na tri načine: kot celo število (%d), kot osmiško celo število (%o) in kot šestnajstiško celo število (%x). Ker želimo, da so števila desno poravnana pod črko ’s’ v besedah Desetisko, Osmisko in Sestnajstisko (glej izpis na sliki 2.2), moramo pošteti, koliko črk vsebuje posamezna beseda. Izpis formatiramo tudi tako, da določimo število mest, ki jih posamezna beseda zasede (desetisko - 9, osmisko - 7 in sestnajstisko - 13). Pravilen izpis (števila so poravnana dva znaka od konca posamezne besede) dosežemo s klicem metode printf v šesti vrstici spodnjega programa.

Rešitev naloge 2-IV.: Izpis tabele za pretvorbo osnove/IzpisSistemi.java

 

Izziv 2-I. o Napiši program za izpis tabele s poštevanko, kot prikazuje spodnja slika.

    |   1   2   3   4   5   6   7   8   9  10 
---------------------------------------------- 
  1 |   1   2   3   4   5   6   7   8   9  10 
  2 |   2   4   6   8  10  12  14  16  18  20 
  3 |   3   6   9  12  15  18  21  24  27  30 
  4 |   4   8  12  16  20  24  28  32  36  40 
  5 |   5  10  15  20  25  30  35  40  45  50 
  6 |   6  12  18  24  30  36  42  48  54  60 
  7 |   7  14  21  28  35  42  49  56  63  70 
  8 |   8  16  24  32  40  48  56  64  72  80 
  9 |   9  18  27  36  45  54  63  72  81  90 
 10 |  10  20  30  40  50  60  70  80  90 100
 

Rešitev izziva 2-I.: Izpis tabele s poštevanko izzivi/Postevanka.java

 

2.6 Argumenti programa

Ob klicu programa iz lupine (npr. iz bash ali cmd) lahko uporabnik poda argumente, s katerimi določa način delovanja programa. Pri nekaterih programih so argumenti obvezni (na primer program man, klican brez argumentov, ne ve, katero stran naj prikaže), nekateri programi argumentov ne uporabljajo (na primer program clear), nekateri programi pa lahko delajo z argumenti ali brez njih - program ls, klican brez argumentov, izpiše seznam vseh datotek trenutnega direktorija, ukaz ls *.java pa izpiše vse datoteke s končnico .java. V zadnjem primeru nizu “*.java” pravimo prvi argument (vsem morebitnim nadaljnjim pa drugi, tretji, .... argument).

Primer klica programov brez argumentov, z enim in z dvema argumentoma
[user@localhost]# clear 
[user@localhost]# ls *.java 
[user@localhost]# cp Test.java Nov.java

Naloga 2-V. Napiši program, ki izpiše vse argumente, ki so bili podani ob klicu.  

Java hrani vse svoje argumente v tabeli, ki je podana kot prvi parameter metode main(). Z drugimi besedami, ob klicu programa, katerega main() metoda je deklarirana kot

 

public static void main(String args[]) { ... }

se vsi morebitni argumenti shranijo v tabelo args. Ker o delu s tabelami za enkrat še ne vemo prav veliko (več o njih bomo spoznali v poglavju ??) omenimo samo dva podatka, ki sta ta hip pomembna:

Upoštevajoč predstavljena dejstva lahko zapišemo rešitev naloge 2-V. Bodite pozorni: števec v for zanki (vrstica 7) teče od 0 do args.length-1.

Rešitev naloge 2-V.: Izpis argumentov programa osnove/Args.java

 

Program Args.java lahko poganjamo iz lupine

[user@localhost]$ java Args To je test 
Stevilo argumentov: 3 
Argument 0: To 
Argument 1: je 
Argument 2: test

ali pa v okolju Netbeans, vendar moramo pri tem storiti naslednje:

2.7 Pretvorba tipov

Naloga 2-VI. Napiši program Racunalo.java, ki izračuna in izpiše vsoto prvih dveh argumentov.  

[user@localhost]$ java Racunalo 3 9 
3 + 9 = 12

Program potrebuje dva argumenta, zato moramo pred začetkom izvajanja preveriti, ali jih je uporabnik podal. Če jih ni, ga moramo poučiti, kako se program uporablja (podobno delajo vsi sistemski ukazi - ob napačnem klicu se izpiše navodilo za uporabo) in končati. To storimo z naslednjim zaporedjem programskih stavkov:

if (args.length != 2) { 
      System.out.println(”Uporaba:_java_Racunalo_x_y”); 
      System.exit(1); 
}

Metoda System.exit(1) konča izvajanje programa. Izhodna koda programa (prvi parameter pri klicu metode exit) se sporoči klicatelju (na primer lupini). Običajno koda 0 pomeni, da se je program končal brez napake, koda, ki je večja od 0, pa pomeni številko napake.

Drugi del programa vzame prva dva argumenta in ju sešteje. Pri tem se pojavi naslednji problem: argumenti (torej elementi tabele args) so tipa String (niz), seštevamo pa lahko le števila. Pred seštevanjem moramo torej oba niza pretvoriti v celi števili. V ta namen uporabimo metodo Integer.parseInt(), ki podani parameter tipa String pretvori v tip int.


images/intString.eps


Slika 2.3: Pretvorba tipov


Včasih potrebujemo tudi pretvorbo v obratni smeri: iz int v String; takrat uporabimo metodo Integer.toString() - glej zgornjo sliko. Podobne metode lahko uporabljamo tudi za pretvorbo v druge primitivne podatkovne tipe. Pri temo moramo smiselno zamenjati besedi Integer in int. Primer: za pretvorbo v realna števila (tip double) uporabimo metodo Double.parseDouble().

Rešitev naloge 2-VI.: Vsota prvih dveh argumentov osnove/Racunalo.java

 

Izziv 2-II. o Popravi program IzpisSistemi.java iz naloge 2-IV tako, da bo uporabnik velikost tabele določil s prvim argumentom pri klicu programa. Če uporabnik argumenta ne poda, naj program izpiše prvih 32 vrstic.  

Rešitev izziva 2-II.: Izpis tabele za pretvorbo med desetiškim, osmiškim in šesnajstiškim številskim sistemom izzivi/IzpisSistemi.java

 

Izziv 2-III. o Napiši program, ki izpiše tabelo za pretvorbo med stopinjami Fahrenheita in stopinjami Celzija, če se formula za preftvorbo glasi:

c = (f - 32)∕1.8.
 

Rešitev izziva 2-III.: Pretvorba Fahrenheit/Celzij izzivi/FC.java

 

Izziv 2-IV. o Popravi program FC.java tako, da bo velikost tabele (spodnjo mejo, zgornjo mejo in korak) določil uporabnik s prvimi tremi argumenti ob klicu programa.  

Rešitev izziva 2-IV.: Pretvorba Fahrenheit/Celzij. Spodnji in zgornjo mejo ter korak določi uporabnik z argumenti ob klicu programa. izzivi/FCPlus.java

 

Izziv 2-V. o Napiši program SIT2EUR.java za pretvorbo med valutama SIT in EUR (1 EUR = 239,64 SIT). Program ob klicu preveri vrednost prvega argumenta. Če je ta enak “SIT”, program opravi pretvorbo iz SIT v EUR, sicer iz EUR v SIT.

Primer klicev in izpisa:

  java SIT2EUR 1 EUR   -> izpis: 1 EUR = 239,64 SIT
  java SIT2EUR 250 SIT -> izpis: 250 SIT = 1,04 EUR  

Rešitev izziva 2-V.: Pretvorba med valutama SIT in EUR. izzivi/SIT2EUR.java

 

2.8 Naključna števila

Naloga 2-VII. Napiši program za naključno izpolnjevanje osnovnega loto listka.  

Osnovni loto listek je listek, na katerem prekrižamo 7 števil med 1 in 39. Naključno izpolnjevanje listka pomeni, da števila prekrižamo brez posebne logike (zapremo oči in križamo, kar nam pride pod svinčnik). Računalnik bi nam pri tem lahko pomagal tako, da bi na zaslon izpisal 7 naključnih števil med 1 in 39, mi pa bi potem ta števila na listku prekrižali.

Za preprosto rešitev naloge potrebujemo for zanko (števec bo tekel od 1 do 7), v posamezni iteraciji te zanke pa moramo izpisati eno naključno število. V ta namen bomo uporabili javanski razred Random, ustvarili njegov primerek in na njem klicali metodo nextInt(). To storimo z naslednjim zaporedjem ukazov:

 

  Random rnd = new Random(); 
  int nakljucnoStevilo = rnd.nextInt();

Metoda nextInt() vrne naključno celo število iz območja [-231...231 - 1]. Za naše potrebe bo ta številka prevelika (mi potrebujemo številko med 1 in 39), zato bomo pri klicu metode podali en parameter (39), s čimer bomo eksplicitno podali območje naključnosti [0...38]. Za pravilen rezultat moramo vrednosti, ki je vrne tako klicana metoda, prišteti 1. Preprosta različica rešitve problema 2-VII je podana v spodnjem programu. Loto - preprosta različica programa osnove/Loto.java

 

Opomba: razred Random moramo pred uporabo uvoziti (ukaz import).

Če večkrat poženemo program Loto.java, ugotovimo naslednje:

Kako se odpravite ti dve težavi, bomo spoznali v naslednjih poglavjih.

2.9 Branje tipkovnice

Naloga 2-VIII. Napiši program za računanje povprečja vpisanih ocen. Podrobneje: program naj na zaslon izpiše besedilo Vpiši oceno: in počaka, da uporabnik vpiše oceno in pritisne tipko Enter. Takrat naj program vpisano oceno prebere in jo prišteje vsoti vseh prebranih ocen. Ta postopek naj se ponavlja, dokler uporabnik ne vpiše ocene 0 (signal za konec vpisovanja). Takrat naj program izračuna povprečje vpisanih ocen (skupna vsota deljeno s številom vpisanih ocen) in ga izpiše.  

Koraki, ki vodijo do rešitve:

Rešitev naloge 2-VIII.: Izpis povprečne ocene osnove/Ocene.java

 

Pozor: pri računanju povprečja

 

double povprecje = (1.0 * vsota / stevilo_ocen);

smo spremenljivko vsota množili z 1.0; tako smo prevajalnik prisilili, da izvaja realno aritmetiko. Spremenljivki vsota in stevilo_ocen sta namreč celoštevilski in zato operacija vsota / stevilo_ocen pomeni celoštevilsko deljenje (na primer: 10 / 3 = 3). Ker pa smo celoten izraz množili z 1.0 (torej z realnim številom), smo prevajalniku nakazali, kakšno deljenje imamo v mislih. Isti učinek bi dosegli s spremembo tipa vsaj enega od operandov:

 

double povprecje = ((double) vsota / stevilo_ocen);

Naloga 2-IX. Napiši igro “uganjevanje števil”. Računalnik si izmisli število, nato uporabnik (igralec) uganjuje. Računalnik mu odgovarja s “Preveč”, “Premalo” ali “BRAVO, uganil si!”. Na koncu naj računalnik izpiše tudi število potez, ki jih je igralec potreboval.  

Rešitev naloge 2-IX.: Igra “uganjevanje števil” osnove/Ugani.java

 

Še kratek napotek za igranje te igre. Če igralec igra povsem naključno, bo v najslabšem primeru za “zmago” potreboval maxStevilo poskusov. Obstaja mnogo boljši način ugibanja, ki število poskusov močno zmanjša. Takole gre: najprej poskusimo srečo s številom na sredini (t.j. maxStevilo/2). Če smo slučajno uspeli, zmagamo, sicer pa razpolagamo z enim podatkom več - vemo namreč, v kateri polovici intervala [1...maxStevilo] se nahaja rešitev (drugo polovico intervala od zdaj naprej ignoriramo). Igro nadaljujemo na enak način: najprej poskusimo srečo s številom, ki je na sredini preostalega intervala; če smo zadeli, zmagamo, v nasprotnem primeru pa vemo, v kateri polovici preostalega intervala (oziroma v kateri četrtini začetnega intervala) se nahaja rešitev. Postopek ponavljamo na enak način do konca; po vsakem ugibanju se nam število kandidatov prepolovi, zato zelo kmalu pridemo do rešitve. Natančneje, za zmago potrebujemo največ log 2(maxStevilo) ugibanj. Primer: če je maxStevilo = 1000, le log 2(maxStevilo) približno enako 10, kar pomeni, da bomo rešitev poiskali v največ 10 korakih. Tak način iskanja, pri katerem na vsakem koraku razpolovimo število kandidatov, imenujemo dvojiško iskanje ali s tujko bisekcija.

2.10 Osnovno o nizih

Naloga 2-X. Napiši program, ki izpiše kratko statistiko niza, ki ga pred tem prebere iz standardnega vhoda. Statistika naj vsebuje: prvo in zadnji črko niza, število besed v nizu ter celotno dolžino niza. Poleg tega naj program niz izpiše še v obrnjenem vrstnem redu (od zadaj naprej).  

Primer izpisa statistike prebranega niza.
Vpisi niz: Danes je lep dan! 
Prva   crka:     D 
Zadnja crka:     ! 
Brez presledkov: Danesjelepdan! 
Stevilo besed:   4 
Celotna dolzina: 17 
Obrnjen niz:     !nad pel ej senaD

Koraki k rešitvi naloge 2-X:

Rešitev naloge 2-X.: Izpis statistike niza osnove/StatistikaNiza.java

 

2.11 Branje iz tekstovne datoteke

Naloga 2-XI. Napiši program, ki prebere tekstovno datoteko CHF2011.txt, v kateri so zbrani podatki o tečaju švicarskega franka za leto 2011 in izpiše datum najvišjega in najnižjega tečaja.  

Rešitev naloge 2-XI.: Izpis največjega in najmanjšega tečaja osnove/Tecaj.java

 

Zgornji program potrebuje še dve pojasnili.

Preverjanje pravilnosti zapisa v datoteki
Pri prenosu datotek po omrežju lahko pride do različnih napak, ki so posledica nedelovanja omrežja ali različnih hekerskih posegov. Programi, ki so namenjeni prenosu datotek, se morajo prepričati, da je datoteka na tej strani omrežja (torej prenesena datoteka) enaka originalu. Kako naj to storijo? Običajno se uporabljajo vnaprej dogovorjeni postopki: računalnik na oni strani omrežja pregleda datoteko in izračuna kontrolni številko, ki to datoteko opisuje (recimo: sešteje ASCII kode vseh znakov v datoteki) in to številko pošlje skupaj z datoteko. Računalnik na tej strani prejme datoteko in omenjeno številko; nato na podlagi prenesene datoteke še sam izračuna kontrolno številko in jo primerja s številko, ki jo je prejel skupaj z datoteko. Če se številki ujemata, sta datoteki verjetno enaki, sicer je treba prenos ponoviti. Omenjeno številko običajno imenujemo kontrolna vsota (angl. checksum). Obstajajo različni postopki za izračun kontrolne številke: CRC, BSD checksum, MD5, SHA-1, SHA-2, ... Postopki se med seboj razlikujejo predvsem po hitrosti in zapletenosti izračuna, velikosti kontrolne številke in zanesljivosti. Zgoraj omenjeno seštevanje vseh znakov je sicer zelo hiter in preprost postopek, ni pa najbolj zanesljiv: če namreč poljubno premešamo vrstni red črk v datoteki, bo kontrolna vsota ostala enaka! Kljub temu se postopek včasih uporablja za hitro preverjanje pravilnosti podatkov, zato ga bomo v spodnjem primeru uporabili tudi mi (opomba: postopek za izračun BSD kontrolne vsote bomo spoznali v poglavju o bitnih operatorjih).

Naloga 2-XII. V zadnji vrstici datoteke ’PodatkiZVsoto.txt’ je zapisana kontrolna številka, ki predstavlja vsoto ASCII kod vseh znakov tekstovne datoteke (znaki za konec vrstice niso všteti v vsoto, za omejitev velikosti kontrolne vsote se uporablja modul 1024). Napiši program, ki preveri, če je številka v zadnji vrstici pravilna.  

Preden se lotimo reševanja problema, si poglejmo pomen dveh dodanih zahtev, ki sta podani v opisu naloge:

Znaki za konec vrstice niso všteti v vsoto.
Tekstovna datoteka ob koncu vsake vrstice vsebuje en ali več “nevidnih” znakov (v sistemu Linux je to znak z ASCII kodo 10 v Windowsih pa sta to znaka s kodo 13 in 10). Če bi datoteko brali “znak po znaku” bi kontrolna vsota vsebovala tudi kode teh nevidnih znakov, ker pa bomo datoteko brali “vrstico po vrstici”, bo java te znake odstranila in jih v kontrolni vsoti ne bo.
Uporaba modula 1024.
Če tekstovna datoteka vsebuje veliko znakov, bi bila njihova vsota zelo velika številka. Temu problemu se lahko ognemo tako, da izberemo poljubno številko (v tem primeru 1024) in vsoto računamo tako, da nikoli ne preseže te številke (namesto vsote uporabimo njen ostanek pri deljenju z izbrano številko).

Primer vsebine datoteke “PodatkiZVsoto.txt”; številka 601 predstavlja vsoto vseh znakov v datoteki po modulu 1024.
Zive naj vsi narodi, 
ki hrepene docakat dan, 
ko, koder sonce hodi, 
prepir iz sveta bo pregnan, 
ko rojak 
prost bo vsak, 
ne vrag, le sosed bo mejak! 
601

Rešitev te naloge je sorazmerno preprosta. Datoteko “PodatkiZVsoto.txt” bomo brali vrstico po vrstici; pri vsaki prebrani vrstici bomo pregledali vse njene znake in kodo posameznega znaka prišteli skupni vsoti. Paziti moramo le, da znakov zadnje vrstice (tam je zapisana kontrolna vsota) ne bomo prišteli vsoti. V ta namen takoj po branju vrstice preverimo, ali je v datoteki še kakšna vrstica; če je, potem nismo v zadnji vrstici (in znake prištejemo vsoti), če pa je ni, smo ravnokar prebrali zadnjo vrstico, potrebna je le še pretvorba prebrane vsote in tipa String v tip int.

Rešitev naloge 2-XII.: Preverjanje kontrolne vsote osnove/CRCcheck.java

 

2.12 Pisanje v tekstovno datoteko

Naloga 2-XIII. Napiši program, ki v datoteko veckratniki.txt zapiše večkratnike števila n (od a * n do b * n). Števila a, b in n preberi iz tipkovnice.  

Rešitev naloge 2-XIII.: Pisanje v tekstovno datoteko osnove/Veckratniki.java

 

Naloga 2-XIV. Napiši program, ki za dano vhodno datoteko izračuna kontrolno vsoto (znakov za konec vrstice ne šteje, vsoto računa po modulu 1024 – glej nalogo 2-XII); program naj vhodno datoteko prepiše v novo datoteko, tej pa naj na koncu doda izračunano vsoto.

Primer izvajanja programa
Vhodna datoteka              Izhodna datoteka 
------------------------------------------------------- 
Zive naj vsi narodi,         Zive naj vsi narodi, 
ki hrepene docakat dan,      ki hrepene docakat dan, 
ko, koder sonce hodi,        ko, koder sonce hodi, 
prepir iz sveta bo pregnan,  prepir iz sveta bo pregnan, 
ko rojak                     ko rojak 
prost bo vsak,               prost bo vsak, 
ne vrag, le sosed bo mejak!  ne vrag, le sosed bo mejak! 
                             601
 

Rešitev naloge 2-XIV.: Računanje kontrolne vsote osnove/CRCgen.java