Datoteke
V tej lekciji se bomo naučili, kako v Javi beremo in pišemo na
datoteke.
Kot verjetno vsi vemo, je datoteka zaporedje podatkov, ki so shranjeni
na disku ali kakem drugem mediju (CD-ROM, disketa). V datotekah
hranimo različne podatke: besedila, preglednice, slike, glasbo,
programe, itn.
Vse datoteke, ki so dostopne na računalniku, so organizirane v
datotečni sistem (angl. "file system"). To je drevesna
struktura, ki sestoji iz direktorijev ali map
(angl. "directory"). Direktoriji lahko vsebujejo podmape,
ki vsebujejo podmape, itn.
Običajno ima računalnik dostop do večih datotečnih sistemov. Pri
operacijskem sistemu Microsoft Windows je vsak datotečni sistem
poimenovan s svojo črko. Datotečna sistema A: in B: sta disketi,
C: je disk, D: pa je CD-ROM. Če je diskov več, potem je se
črkujejo po vrsti C:, D:, E:.
Vsaka datoteka ima
ime in stoji v neki mapi.
Polno
ime datoteke dobimo tako, da zložimo skupaj njeno ime in
mapo. Denimo, da je datoteka
foo.txt
na disku
C:
, v mapi
bla
, ki je v podmapi
tralala
. Potem je polno ime datoteke
C:\tralala\bla\foo.txt
Vidimo, da imena dorektorijev ločimo z znakom
\
. To
velja za Microsoft Windows, medtem ko na Linuxu in Unixu
uporabljamo znak
/
. Kadar pišemo znak
\
v Javi
v nizu, moramo napisati dvojni
\\
.
Preden lahko z datoteke beremo ali nanjo pišemo, jo moramo
najprej odpreti. Glede na to, ali želimo iz datoteke
brati podatke, ali pa vanjo pisati, jo odpremo bodisi za
branje bodisi za pisanje.
Branje z datotek
Oglejmo si najprej primer, ko datoteko odpremo za branje.
Denimo, da želimo brati z datoteke
foo.txt
. Ker je Java
objektni programski jezik, se datoteko odpre tako, da se
preprosto naredi nov objekt ustreznega razreda:
FileReader d = new FileReader("foo.txt"); |
S tem smo naredili nov objekt
d
, ki bo sam odprl
datoteko
foo.txt
. Z datoteke lahko nato beremo z metodo
read(char[], int, int)
. V večini
primerov želimo brati posamezne vrstice, česar pa metoda
read
ne omogoča. Zato običajno naredimo še en objekt
razreda
BufferedReader
,
ki ga nato uporabljamo za branje posameznih vrstic:
BufferedReader datoteka = new BufferedReader(d); |
Objekt
datoteka
spada v razred
BufferedReader
,
ki vsebuje metodo
readLine()
za branje ene vrstice. Oglejmo si uporabo datotek v celotnem
programu. Napišimo program
IzpisiDatoteko.java
, ki
prebere vrstice dane datoteke in jih izpiše na zaslon:
IzpisiDatoteko.java |
---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| import java.io.*;
public class IzpisiDatoteko {
public static void main(String[] args) throws IOException {
String ime = args[0];
BufferedReader datoteka = new BufferedReader(new FileReader(ime));
while(datoteka.ready()) {
System.out.println(datoteka.readLine());
}
datoteka.close();
}
} |
V 1. vrstici vidimo ukaz import java.io.*
, s
katerim Javi povemo, da bomo uporabljali razrede in metode iz
knjižnice java.io
. Ta knjižnica vsebuje vse potrebno za
delo z datotekami.
V 4. vrstici vidimo določilo throws
IOException
, s katerim Javi povemo, da metoda
main
lahko vrže izjemo IOException
(spomnimo se, da moram v Javi povedati, katere izjeme metoda
vrže). Ta izjema se zgodi, če na primer hočemo odpreti
datoteko, ki ne obstaja.
V 6. vrstici vidimo, da dobimo ime datoteke podano kot argument
v ukazni vrstici.
V 8. vrstici vidimo, kako se naredi nov objekt
razreda BufferedReader
. Objekt shranimo v
spremenljivko z imenom datoteka
in ga uporabljamo
za branje z datoteke.
V
10. vrstici vidimo, da z metodo
ready()
preverimo, ali objekt
datoteka
vsebuje še kako
vrstico za branje. Metoda
ready()
vrne
true
, če je v datoteki na voljo vrstica za branje,
in
false
, če je datoteke že konec.
V
11. vrstici vidimo, da z metodo
readLine()
preberemo naslednjo vrstico z datoteke. Spomnimo se, da smo
to metodo že uporabili za branje s standardnega vhoda.
V
14. vrstici vidimo, da na koncu
datoteko
zapremo z metodo
close().
To naredimo vedno, ko datoteke ne potrebujemo več.
Ne pozabite preizkusiti programa!
Naloga 1
Napiši program PrestejVrstice.java
, ki izpiše
število vrstic v dani datoteki (datoteka je "dana" z imenom
v ukazni vrstici, se pravi v args[0]
).
[
rešitev]
Pisanje na datoteke
Zdaj pa si še oglejmo, kako pišemo na datoteko. Za pisanje na
datoteko
bar.txt
naredimo objekt razreda
FileWriter
:
FileWriter d = new FileWriter("bar.txt"); |
Tako kot pri branju z datotek je tudi pisanje na datoteko z
objektom razreda
FileWriter
nepraktično. Bolj prikladen
je objekt
PrintWriter
:
PrintWriter datoteka = new PrintWriter(d); |
Objekt razreda
PrintWriter
vsebuje metodi
println
in
print
,
ki ju že uporabljamo za izpisovanje na zaslon. Sedaj pa jih znamo
uporabljati tudi za zapisovanje na datoteke:
ZapisiIzrek.java |
---|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| import java.io.*;
public class ZapisiIzrek {
public static void main(String[] args) throws IOException {
String ime = args[0];
PrintWriter datoteka = new PrintWriter(new FileWriter(ime));
datoteka.println("Moj najljubsi izrek o trikotnikih je:");
datoteka.println();
datoteka.println("Simetrala kota se s simetralo nasprotne stranice");
datoteka.println("seka na ocrtanem krogu.");
datoteka.close();
}
} |
> javac ZapisiIzrek.java
> java ZapisiIzrek poskus.txt |
Kam se je zapisal izrek o trikotnikih? Na zaslonu ga ni? Seveda
ne, saj smo uporabili metodo
println()
iz objekta
datoteka
in
ne iz objekta
System.out
,
kot smo to počeli do sedaj. Objekt
datoteka
je zapisal
vse v datoteko
poskus.txt
.
Opozorilo: zelo pomembno je, da na datoteko
zapremo z metodo close()
, ko smo končali
zapisovanje vanjo, sicer se lahko zgodi, da se podatki ne bodo
pravilno zapisali! (Poskusite, kaj se zgodi, če pobrišete ukaz
datoteka.close()
).
Naloga 2
Napiši program Kopiraj.java
, ki vsebino ene
datoteka prepiše na drugo datoteko. Imeni datotek sta podani
na ukazni vrstici.
[
rešitev]
Naloga 3
Napiši program
Sestej.java
, ki z ukazne vrstice
sprejme ime datoteke, v kateri so zapisana cela števila,
vsako v svoji vrsti. Program naj izpiše na zaslon vsoto
števil iz datoteke. Na primer, če je v datoteki
foo.txt
zapisano
potem se zgodi tole:
> java Sestej foo.txt
126 |
Naloga 4
Napiši program
Ostevilci.java
, ki z ukazne vrstice
sprejme ime vhodne datoteke
vh
in izhodne datoteke
iz
. Nato prepiše vhodno datoteko na izhodno
datoteko, pri čemer vrstice v izhodni datoteki oštevilči.
Med številko in preostanek vrstice naj program postavi
tabulator (znak
'\t'
). Na primer, če je vsebina
datoteke
vrba.txt
O Vrba! srečna, draga vas domača,
kjer hiša mojega stoji očeta;
de b' uka žeja me iz tvojga sve'ta
speljala ne bila, goljfiva kača!
Ne vedel bi, kako se v strup prebrača
vse, kar srce si sladkega obeta;
mi ne bila bi vera v sebe vzeta,
ne bil viharjov no'tranjih b' igrača!
Zvesto' srce in delavno ročico
za doto, ki je nima miljonarka,
bi bil dobil z izvoljeno devico;
mi mirno plavala bi moja barka,
pred ognjam dom, pred točo mi pšenico
bi bližnji sosed va'roval - svet' Marka. |
in poženemo program
> java Ostevilci vrba.txt foo.txt |
potem je vsebina datoteke
foo.txt
1 O Vrba! srečna, draga vas domača,
2 kjer hiša mojega stoji očeta;
3 de b' uka žeja me iz tvojga sve'ta
4 speljala ne bila, goljfiva kača!
5
6 Ne vedel bi, kako se v strup prebrača
7 vse, kar srce si sladkega obeta;
8 mi ne bila bi vera v sebe vzeta,
9 ne bil viharjov no'tranjih b' igrača!
10
11 Zvesto' srce in delavno ročico
12 za doto, ki je nima miljonarka,
13 bi bil dobil z izvoljeno devico;
14
15 mi mirno plavala bi moja barka,
16 pred ognjam dom, pred točo mi pšenico
17 bi bližnji sosed va'roval - svet' Marka. |
Naloga 5
Napiši metodo prestej_besede
, ki sprejme niz znakov
in vrne število besed v nizu. Za besedo šteje poljubno
neprazno zaporedje znakov med dvema presledkoma. Za
presledke štejemo tudi tabulator '\t'
in znak za
novo vrsto '\n'
.
Na primer, niz znakov "Kdor ne delja, naj ne je."
ima 6 besed, niz znakov "++ !! ax"
ima 3 besede,
niz "Ena dva,tri stiri pet"
pa ima 4 besede. (Več
zaporednih presledkov seveda šteje kot en presledek.)
Naloga 6
Namig
Napiši program, ki prešteje število besed v dani datoteki.
Uporabi metodo prestej_besede
iz prejšnje naloge.