Luvussa tutustutaan yhteen tapaan kirjoittaa ja lukea nimettyjä tekstitiedostoja. Luku alkaa tiedostojen hallinnan yleisen välineen, luokan File, esittelyllä.
Edellisen luvun tapaan tämäkin luku antaa esimerkkejä valmiiden välineiden käyttötapojen etsimisestä.
Luokalla on mm. konstruktori:
public File(String path)joka luo File-olion. Parametri on tiedostonimi, tarkemmin sanottuna ns. polkunimi.
Polkunimi (pathname) tarkoittaa tiedoston nimeä
mahdollisine hakemistopolkuineen. Esimerkiksi
Unix/Linux-järjestelmissä ne voivat olla mm. seuraavanlaisia:
tiedosto
td.sto
hakemisto/alihakemisto/td.sto (nykyhakemiston alihakemisto ...)
/hakemisto/alihakemisto/td.sto (juurihakemiston alihakemisto ...)
../td.sto (ylemmän tason hakemiston td.sto)
../../alihak/td.sto (.. jne...)
File-oliolle on käytettävissä monia metodeita, mm.
public boolean exists() // palauttaa true, jos tiedosto on olemassa public long length() // antaa tiedoston pituuden public boolean renameTo(File dest) // uudelleennimeää, true jos onnistui public boolean delete() // poistaa tiedoston, true jos onnistui public String getName() // antaa tiedoston nimen ... ...Näiden käytöstä saadaan joitakin esimerkkejä jatkossa.
Luokan ilmentymiä, tulostustiedostoja(!), luodaan mm. konstruktorilla:
public PrintWriter(OutputStream out, boolean autoFlush)Huom: Jälkimmäinen parametri ohjaa ns. tulostuspuskurin tietojen siirtämistä varsinaiseen tiedostoon. Kun parametrin asettaa trueksi, tiedostoa ei tarvitse itse sulkea (close()).
Luokassa PrintWriter ei ole konstruktoria, jolle voisi antaa tiedostonimen. Niinpä seuraava ongelma on löytää jokin tapa kertoa, minne kirjoitetaan. Parametrin tyyppi OutputStream on abstrakti luokka, siitä ei siis voi luoda edes ilmentymiä! Mutta sillä on aliluokka FileOutputStream, jolla on mm. konstruktorit:
public FileOutputStream(String name) throws IOException public FileOutputStream(String name, boolean append) throws IOException public FileOutputStream(File file) throws IOExceptionKaksi ensimmäistä saa tiedostonimen parametrina, kolmas File-olion. (Toinen konstruktoreista tarjoaa mahdollisuuden kirjoittaa olemassaolevan tiedoston loppuun: kun paramertiksi append annetaan true, kirjoitettava liitetään olemassaolevaan tiedostoon.)
Jos halutaan kirjoittaa tiedosto "tulos.txt", voidaan siis ohjelmoida:
import java.io.*; ... PrintWriter tulos = new PrintWriter( new FileOutputStream("tulos.txt"), true // ); ... tulos.println("Hip hei!"); ...Tässä siis luodaan nimetystä tiedostosta FileOutputStream-olio, joka annetaan samantien parametriksi PrintWriter-luokan konstruktorille.
Huom: Tämäntapainen menettely on Javan valmiiden välineiden käyttämisessä tavallista: halutaan tietynlainen käyttötapa (PrintWriter-luokan mukavat metodit) ja käytössä on tietynlainen lähtökohta (tiedoston nimi String-oliona). Ratkaisuja etsitään luokkien suhteita ja konstruktoreita tutkimalla.
Esimerkki 1: Laaditaan sovellus, jolla voi kirjoittaa näppäimistöltä tekstiä tiedostoon "juttu.txt" (Talleta1.java):
import java.io.*; public class Talleta1 { public static void main(String[] args) throws IOException { PrintWriter tulos = new PrintWriter( new FileOutputStream("juttu.txt"), true // ! ); System.out.println("Kirjoittamasi teksti menee tiedostoon juttu.txt"); System.out.println("(ctrl-d lopettaa!)\n"); String rivi; while ((rivi = Lue.rivi()) != null) tulos.println(rivi); System.out.println("Työt tehty!\n"); } }Esimerkissä annetaan main-metodille lupa kaatua, koska konstruktorin kutsu new FileOutputStream("juttu.txt") voi aihettaa poikkeuksen!
Ohjelma on ainakin kahdesta syystä vähän huono:
import java.io.*; public class Talleta2 { public static void main(String[] args) throws IOException { System.out.println("Minne tulostetaan?"); String tulNimi=Lue.rivi(); File tulTd = new File(tulNimi); if (tulTd.exists()) { System.out.println("Tiedosto "+tulNimi+" on jo olemassa!"); System.out.println("Haluatko korvata sen uudella (k = kyllä)?"); if (Lue.merkki() != 'k') return; // keskeytetään kaikki! } PrintWriter tulos = new PrintWriter( new FileOutputStream(tulTd), true // ! ); System.out.println("Kirjoittamasi teksti menee tiedostoon "+tulNimi); System.out.println("(ctrl-d lopettaa!)\n"); String rivi; while ((rivi = Lue.rivi()) != null) tulos.println(rivi); System.out.println("Työt tehty!\n"); } }
Tekstitiedostoa voidaan lukea riveittäin esimerkiksi seuraavasti:
import java.io.*; ... BufferedReader syotto = new BufferedReader( new InputStreamReader( new FileInputStream(?????) ) ); ... String rivi = syotto.readLine(); ...Luokan FileInputStream konstruktorin parametriksi kelpaa tiedostopolku tai File-olio.
Esimerkki 3: Laaditaan sovellus, joka listaa kuvaruudulle tiedoston "juttu.txt" (Listaa1.java):
import java.io.*; class Listaa1 { public static void main(String[] args) throws IOException { BufferedReader syotto = new BufferedReader( new InputStreamReader( new FileInputStream("juttu.txt") ) ); String rivi; while ((rivi = syotto.readLine()) != null) System.out.println(rivi); } }Tätäkin ohjelmaa voi vähän kehitellä. Ohjelma osaa tulostaa aina vain tiedoston "juttu.txt". Ja jos tiedosto puuttuu, saadaan systeemin antama "käyttäjävihamielinen" virheilmoitus.
Esimerkki 4: Käytetään hyväksi File-luokkaa (Listaa2.java):
import java.io.*; class Listaa2 { public static void main(String[] args) throws IOException { System.out.println("Minkä tiedoston haluat nähdä?"); String syoNimi=Lue.rivi(); File syoTd = new File(syoNimi); if (!syoTd.exists()) { System.out.println("Tiedostoa "+syoNimi+" ei löydy!"); return; // keskeytetään kaikki! } BufferedReader syotto = new BufferedReader( new InputStreamReader( new FileInputStream(syoTd) ) ); String rivi; while ((rivi = syotto.readLine()) != null) System.out.println(rivi); } }
Jos käsiteltäviä tiedostoja on aina vain yksi, voidaan laatia luokan Lue kaltaisia kirjastoluokkia.
"Oikeat" luokat, joista luodaan ilmentymiä, antavat enemmän mahdollisuuksia: ohjelmassa voi luoda useampia olioita, tiedostoja, luettaviksi ja kirjoitettaviksi.
Tiedostojenkäsittelyluokkia suunnitellessa joutuu tekemään useita valintoja, jotka vaikuttavat luokkien käyttötapaan (olkoon tiedostoluokka nimeltään Tiedosto ja sovellus Sovellus):