4. Tiedostot

Tiedostot

Tiedostojen käyttäminen on tavallinen tapa tallentaa tietoa, jonka tulee säilyä muistissa ohjelman suorituskertojen välillä.

Tekstitiedosto muodostuu joukosta tekstirivejä. Seuraavassa on yksinkertainen tekstitiedosto, jossa on kolme riviä:

Tämä rivi aloittaa tiedoston.
Sitten tulee toinen rivi.
Kolmas rivi on jo viimeinen.

Tekstitiedostojen etuna on, että niitä on helppo käsitellä tavallisilla tekstieditoreilla ja eri ohjelmointikielissä. Kaikki tällä kurssilla käsiteltävät tiedostot ovat tekstitiedostoja.

Tiedostosta lukeminen

Seuraava ohjelma lukee ja tulostaa tekstitiedoston sisällön:

import java.util.*;
import java.io.*;

public class TiedostostaLuku {
    public static void main(String[] args) throws Exception {
        Scanner tiedosto = new Scanner(new File("esimerkki.txt"));
        while (tiedosto.hasNextLine()) {
            String rivi = tiedosto.nextLine();
            System.out.println(rivi);
        }
    }
}

Ohjelman tulostus voi olla seuraava:

Tämä rivi aloittaa tiedoston.
Sitten tulee toinen rivi.
Kolmas rivi on jo viimeinen.

Kokeile, että saat ohjelman toimimaan omalla tiedostollasi. Tässä tiedoston nimenä on esimerkki.txt, ja tiedoston tulee olla NetBeans-projektin päähakemistossa, jotta ohjelma löytää tiedoston.

Tiedoston lukeminen onnistuu Scanner-olion kautta samaan tapaan kuin käyttäjän kirjoittaman tekstin lukeminen, kunhan oliolle annetaan tiedostoa vastaava File-olio. Luokan File käyttäminen vaatii uuden import-rivin koodin alkuun.

Lisäksi metodin main loppuun on lisätty throws Exception, joka liittyy tiedostojen käsittelyssä mahdollisesti tapahtuvien virheiden käsittelyyn. Palaamme tähän asiaan seuraavassa luvussa.

Tiedostoon tallentaminen

Seuraava ohjelma tallentaa nimiä tiedostoon:

import java.io.*;
import java.util.*;

public class TiedostoonTallennus {
    public static void main(String[] args) throws Exception {
        PrintWriter tiedosto = new PrintWriter(new File("nimet.txt"));
        tiedosto.println("Aapeli");
        tiedosto.println("Maija");
        tiedosto.println("Uolevi");
        tiedosto.close();
    }
}

Tämä ohjelma saa aikaan seuraavan tiedoston:

Aapeli
Maija
Uolevi

Tässä on käytössä PrintWriter-olio, jonka avulla tiedostoon voi tulostaa samaan tapaan kuin käyttäjän näytölle. Viimeinen komento close sulkee tiedoston. Älä unohda komentoa, koska muuten osa riveistä saattaa jäädä puuttumaan tiedoston lopusta.

Huomaa, että jos tiedosto on olemassa valmiiksi, ohjelma korvaa tiedoston sisällön. Jos tiedostoa ei ole olemassa valmiiksi, ohjelma luo uuden tiedoston.

Esimerkki: Sanalista

Tiedostossa sanalista.txt on Kotimaisten kielten tutkimuskeskuksen julkaisema nykysuomen sanalista.

Seuraava ohjelma etsii listalta kaikki palindromisanat eli sanat, joiden kirjaimet ovat samat alusta loppuun ja lopusta alkuun luettuna:

import java.util.*;
import java.io.*;

public class PalindromiSanat {
    public static boolean palindromi(String sana) {
        int pituus = sana.length();
        for (int i = 0; i < pituus / 2; i++) {
            if (sana.charAt(i) != sana.charAt(pituus - i - 1)) {
                return false;
            }
        }
        return true;
    }

    public static void main(String[] args) throws Exception {
        Scanner tiedosto = new Scanner(new File("sanalista.txt"));
        while (tiedosto.hasNextLine()) {
            String sana = tiedosto.nextLine();
            if (palindromi(sana)) {
                System.out.println(sana);
            }
        }
    }
}

Ohjelman tulostus on seuraava:

ajaja
akka
ala
alla
autioitua
ele
enne
hah
heh
huh
hyh
häh
imaami
isi
niin
oho
olo
opo
otto
piip
pop
sadas
sammas
sees
siis
sus
suuruus
sylys
sytytys
syys
syöppöys
tuut
tyyt
tööt
utu
yty
älä
ämmä
ässä

Tiedostoformaatti

Tiedostoformaatti tarkoittaa tapaa, jolla ohjelma tallentaa tietonsa tiedostoon. Tiedostoformaatti on ohjelmoijan päätettävissä, ja vaihtoehtoja on yleensä monia. Ainoa vaatimus on, että ohjelma tallentaa ja lukee tiedot samaa formaattia käyttäen.

Esimerkki: Ostoslista

Seuraavassa ohjelmassa käyttäjä voi lisätä tavaroita ostoslistalle sekä tallentaa ja ladata ostoslistan.

import java.util.*;
import java.io.*;

public class Ostoslista {
    private static Scanner input = new Scanner(System.in);

    private static String tiedostonNimi = "ostoslista.txt";
    private static ArrayList<String> lista = new ArrayList<String>();

    private static void lisaaListalle() {
        System.out.print("Tavaran nimi: ");
        String tavara = input.nextLine();
        lista.add(tavara);
    }

    private static void tulostaLista() {
        System.out.println("Listan sisältö:");
        for (String tavara : lista) {
           System.out.println(tavara);
        }
    }

    private static void tallennaLista() throws Exception {
        PrintWriter tiedosto = new PrintWriter(new File(tiedostonNimi));
        int tavaramaara = lista.size();
        tiedosto.println(tavaramaara);
        for (String tavara : lista) {
            tiedosto.println(tavara);
        }
        tiedosto.close();
    }

    private static void lataaLista() throws Exception {
        Scanner tiedosto = new Scanner(new File(tiedostonNimi));
        lista.clear();
        int tavaramaara = Integer.parseInt(tiedosto.nextLine());
        for (int i = 0; i < tavaramaara; i++) {
            String tavara = tiedosto.nextLine();
            lista.add(tavara);
        }
    }


    public static void main(String[] args) throws Exception {
        System.out.println("1: Lisää tavara");
        System.out.println("2: Tulosta lista");
        System.out.println("3: Tallenna lista");
        System.out.println("4: Lataa lista");
        System.out.println("5: Sulje ohjelma");
        while (true) {
            System.out.print("Anna komento: ");
            String komento = input.nextLine();
            if (komento.equals("1")) {
                lisaaListalle();
            }
            if (komento.equals("2")) {
                tulostaLista();
            }
            if (komento.equals("3")) {
                tallennaLista();
            }
            if (komento.equals("4")) {
                lataaLista();
            }
            if (komento.equals("5")) {
                return;
            }
        }
    }
}

Tässä tiedostoformaattina on, että tiedoston ensimmäisellä rivillä lukee tavaroiden määrä ja kullakin seuraavalla rivillä lukee yhden tavaran nimi.

Ohjelman ensimmäinen suorituskerta:

1: Lisää tavara
2: Tulosta lista
3: Tallenna lista
4: Lataa lista
5: Sulje ohjelma
Anna komento: 1
Tavaran nimi: selleri
Anna komento: 1
Tavaran nimi: retiisi
Anna komento: 1
Tavaran nimi: nauris
Anna komento: 2
Listan sisältö:
selleri
retiisi
nauris
Anna komento: 3
Anna komento: 5

Nyt tiedoston ostoslista.txt sisältö on seuraava:

3
selleri
retiisi
nauris

Ohjelman toinen suorituskerta:

1: Lisää tavara
2: Tulosta lista
3: Tallenna lista
4: Lataa lista
5: Sulje ohjelma
Anna komento: 4
Anna komento: 2
Listan sisältö:
selleri
retiisi
nauris
Anna komento: 5