You are on page 1of 6

Objektno orijentisano projektovanje, VIŠER 2015

Skripta: Rad sa tekstualnim datotekama


Rad sa fajlovima i folderima
Za rad sa tekstualnim datotekama, njihovim pravljenjem, čitanjem podataka, upisom podataka i
brisanjem, potrebno je znati klase koje u Javi služe za programsku reprezentaciju datoteka.
File klasa je klasa koja predstavlja putanje za fajlove i foldere u abstraktnom maniru. Sam objekat
predstavlja fajl/folder na računaru. Koristi se za kreiranje, pretrage, obrade, brisanje itd.

Kreiranje fajla
Konstruktor za neki određeni fajl prima kao argument putanju do datog fajla, odnosno potencijalnu
putanju gde se taj fajl nalazi. Program ne može da zna da li taj fajl zaista postoji. Pretpostavimo da
nam je u zadatku dato da napravimo novi tekstualni fajl (File klasa ne brine se o ekstenziji fajla,
odnosno možemo da kreiramo bilo koji tip!).
Za početak kreirajmo fajl „test.txt“. Prvi korak je kreiranje putanje ka datom fajlu:
File f = new File("test.txt");
Ovim smo ostvarili samo relaciju između objekta u Javi, ali i dalje nemamo dokaze da dati fajl postoji.
Metoda koju možemo da iskoristimo je createNewFile() koja će kreirati fizičku reprezentaciju fajla na
našem računaru. Metoda vraća true ako može da kreira fajl, a false ako nije uspešno kreiran fajl. Ova
metoda takođe može baciti izuzetak IOException pa je potrebno kreiranje fajla i dalje funkcionalnosti
nad njim da izvršavamo unutar try/catch bloka. Kod za kreiranje prvog fajla glasi:
import java.io.*;
public class JAVA_Fajlovi {
public static void main(String[] args) {
try {
File f = new File("test.txt");
if(f.createNewFile()) {
System.out.println("Fajl je uspešno kreiran!");
} else {
System.out.println("Fajl ne može biti kreiran!");
}
} catch (IOException ex) {
System.err.println("Greška: " + ex);
}
}
}
Kada se pokrene program dobijamo poruku u terminalu:
Fajl je uspešno kreiran!
Kako ne znamo gde se nalazi naš novo kreirani fajl, možemo dobiti fizičku lokaciju koristeći metodu
getAbsolutePath() koja će nam vratiti fizičku putanju za dati fajl. Prvo treba obrisati već kreirani txt fajl
i on se nalazi u okviru vašeg projekta. Sada ispod poruke o uspešno kreiranom fajlu treba dodati
sledeći kod za prikaz absolutne putanje:
Objektno orijentisano projektovanje, VIŠER 2015

System.out.println("Absolutna putanja je: " + f.getAbsolutePath());


Izlaz koji se dobija u terminalu (u skladu sa lokacijom projekta za demonstraciju) je:
Absolutna putanja je: E:\VISER\OOP 2014\Zbirka\JAVA_Fajlovi\test.txt
Sada problem je što se ovaj kod se izvršava ako fajl ne postoji, a trebalo bi da pre toga uopšte pitamo
da li fajl postoji odnosno da li ima potrebe da se kreira novi fajl. Metoda exists() vrati će true ili false
ako fajl postoji odnosno ne postoji. Uz modifikacije koda dobija se sledaći kod:
import java.io.*;
public class JAVA_Fajlovi {
public static void main(String[] args) {
try {
File f = new File("test.txt");
if(!f.exists()) {
if(f.createNewFile()) {
System.out.println("Fajl je uspešno kreiran!");
System.out.println("Absolutna putanja je: " +
f.getAbsolutePath());
} else {
System.out.println("Fajl ne može biti kreiran!");
}
}
} catch (IOException ex) {
System.err.println("Greška: " + ex);
}
}
}
Kreiranje foldera
Metode za kreiranje foldera su mkdir() i mkdirs(). Razlika je u tome što mkdir() će praviti folder samo
ako postoji cela putanja npr. ako je putanja za kreiranje foldera put/do/folder i folder „do“ ne postoji
metoda neće kreirati direktorijum. Sa druge strane mkdirs() će kreirati sve foldere koji fale na datoj
putanji uključujući i folder koji želimo da kreiramo. Obe metode vraćaju true ili false u zavisnosti od
uspeha kreiranja foldera.Za ove narebe ne treba try/catch blok. Kreirajmo putanju „put/do/folder“ u
programu:
import java.io.*;
public class JAVA_Fajlovi {
public static void main(String[] args) {
File f = new File("put/do/foldera");
if(f.mkdirs()) {
System.out.println("Folder je uspešno kreiran!");
System.out.println("Absolutna putanja je: " +
f.getAbsolutePath());
}
}
}
Izlaz u terminalu je sledeći:
Folder je uspešno kreiran!
Objektno orijentisano projektovanje, VIŠER 2015

Absolutna putanja je: E:\VISER\OOP 2014\Zbirka\JAVA_Fajlovi\put\do\foldera


isFile() i isDirectory()
Dve metode koje su značajne su – isFile() i isDirectory koje nam dozvoljavaju da ispitamo da li radimo
sa fajlom ili sa direktorijumom. Vraćaju true ili false u zavisnosti od tipa. Primer implementacije koda
je:
File f1 = new File("put/do/foldera");
File f2 = new File("test.txt");
if(f1.exists()) {
System.out.println("Fajl f1 je datoteka: " + f1.isFile());
System.out.println("Fajl f1 je direktorijum: " + f1.isDirectory());
}

if(f2.exists()) {
System.out.println("Fajl f2 je datoteka: " + f2.isFile());
System.out.println("Fajl f2 je direktorijum: " + f2.isDirectory());
}
Brisanje fajla / foldera
Metoda za brisanje fajla, odnosno foldera je delete(). Implementacija koda je sledeća:
File f = new File("test.txt");
if(f.exists()) {
if(f.delete()) {
System.out.println("Fajl je obrisan!");
}
}
Izlistavanje fajlova i foldera
Da bi se izlistali fajlovi i direktorijumi, postoji naredba list() koja će za dati direktorijum vratiti niz
stringova sa imenima fajlova i direktorijuma koji se u njemu nalaze. Dat je primer sa folderom
„test_folder“ koji ima sledeću strukturu:

Kod za dobijanje ove liste glasi:


File f = new File("test_folder");
if(f.exists()) {
String[] lista = f.list();
for(String fajl : lista) {
System.out.println(fajl);
}
}
Druga naredba koja će da vrati fizičke reprezentacije fajlova i foldera je listFiles(). Povratna vrednost
je niz fajlova nad kojim se mogu raditi fizičke modifikacije.
Objektno orijentisano projektovanje, VIŠER 2015

Kod za implementaciju je:


File f = new File("test_folder");
if(f.exists()) {
File[] lista = f.listFiles();
for(File fajl : lista) {
System.out.println(fajl.getAbsolutePath());
}
}

Ovo su neke osnovne funkcije koje se odnose na rad sa fajlovima i folderima. U nastavku ćemo videti
kako da čitamo i upisujemo sadržaj iz tekstualnih datoteka

Čitanje i upis sadržaja u tekstualne datoteke


Čitanje celog sadržaja u jedan string
Znamo da datoteka nije ništa drugo nego skup bajtova na jednoj fizičkoj lokaciji. U Javi postoji klasa
Files (nemojte pomešati sa File klasom) koja ima statičku metodu readAllBytes(). Kao parametar se
šalje putanja. Ova putanja nije tipa File, odnosno ne kreira se fizička reprezentacija fajla. Objekat koji
koristimo je tipa Path odnosno pravimo fizičku reprezentaciju putanje. Kako se objekti tipa Path ne
mogu instancirati, koristi se pomoćna klasa Paths koja ima metodu get() koja vraća objekat fizičke
reprezentacije putanje. Sada ćemo da iskoristimo metodu readAllBytes(). Ova metoda vratiće niz
byte-ova koje treba pretvoriti u karaktere. Ako se setimo da String tip podataka ima svoje
konstruktore od kojih jedan prihvata baš niz karaktera kao parametar, onda možemo da prikažemo
sadržaj na sledeći način:
import java.io.*;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;

public class JAVA_Fajlovi {


public static void main(String[] args) {
try {
byte[] encoded = Files.readAllBytes(Paths.get("test.txt"));
String s = new String(encoded,Charset.forName("UTF-8"));
System.out.println(s);
} catch(IOException ex) {
System.err.println(ex);
}
}
}

Problem sa ovakvim načinom čitanja je da sam niz bajtova koji kreiramo može biti i nekoliko puta
veći od veličine naše datoteke. Ova način se preporučuje kada znate da raditi sa datotekama malih
veličina ili raspoloživim memorijskim prostorom.
Objektno orijentisano projektovanje, VIŠER 2015

Čitanje sadržaja red po red


Drugi i bolji način po bafer naše aplikacije je da se čitaju podaci red po red iz datoteke. Postoje dva
načina na koja možemo da čitamo sadržaj. Prvi način je korišćenjem metode readAllLines() iz klase
Files. Povratna vrednost je objekat tipa List. ArrayList nasleđuje List klasu, pa možemo direktno
konvertovati listu u ArrayList-u. Kod izgleda ovako:
try {
ArrayList<String> lines =
(ArrayList)Files.readAllLines(Paths.get("test.txt"), Charset.forName("UTF-8"));
for(String s : lines) System.out.println(s);
} catch (IOException ex) {
System.err.println(ex);
}

Drugi način na koji možemo da čitamo datoteke je korišćenjem BufferedReader klase. Korišćenje
ovog metoda zahteva i dodatne klase pa je potrebno da razjasniti šta koja klasa radi. Prva klasa koju
moramo da koristimo je FileInputStream. Ova klasa u konstruktoru prima fajl (objekat File klase) sa
kojim želimo da komuniciramo. Ovim se otvara tok, odnosno konekcija sa datim fajlom. Dok je ovaj
tok otvoren drugi korisnici ne mogu da pristupaju tom fajlu. Sledeća klasa je InputStreamReader koja
služi da čita podatke iz toka. Ulazni parametar je objekat tipa InputStream odnosno FileInputStream
u našem slučaju. Ova klasa čita bajtove (ovu klasu možemo koristiti kao i u slučaju za čitanje celog
sadržaja zbog ove mogućnosti) što nama ne odgovara ako već želimo da čitamo svaki red datoteke.
Zbog toga potrebno je te bajtove konvertovati u smislene podatke. BufferedReader ima metodu
readLine() koja će da interpretira niz byte-ova do byte-a koji označava prelazak u novi red, odnosno
čitaće podatke red po red. Čitanje reda će se obaviti smeštanjem sadržaja u pomoćnu promenljivu
sve dok sadržaja ima. Kada to ne bude bio slučaj, znači da smo došli do kraja fajla. Kod izgleda ovako:
try {
FileInputStream fis = new FileInputStream("test.txt");
InputStreamReader isr = new InputStreamReader(fis, Charset.forName("UTF-
8"));
BufferedReader bfr = new BufferedReader(isr);

ArrayList<String> lines = new ArrayList<String>();


String linija = "";
while ((linija = bfr.readLine()) != null)
lines.add(linija);
bfr.close();
isr.close();
fis.close();
for(String s : lines) System.out.println(s);
} catch (IOException ex) {
System.err.println(ex);
}
Objektno orijentisano projektovanje, VIŠER 2015

Upis sadržaja u datoteku


Sadržaj može biti upisan u datoteku na više načina. Jedan od načina je korišćenjem klase Files i
metode write() koja će upisati sadržaj u datoteku. write naredba upisuje ili karaktere ili bytove u
datoteku tako da je potrebno prvo konvertovati dati sadržaj. Još jedan od parametara je da li se briše
stari sadržaj ili dodaje novi (append). Kod izgleda ovako, a zatim ćemo disktutovati o tome šta je treći
parametar funkcije write():
byte[] bytes = ("Neki string koji želimo da upišemo" +
System.getProperty("line.separator") + "Ima i više
redova").getBytes(Charset.forName("UTF-8"));;
try {
Files.write(Paths.get("test.txt"), bytes, StandardOpenOption.WRITE);
} catch (IOException ex) {
System.err.println(ex);
}

Ovde postoje dve stvari sa kojima se srećemo. Prva je System.getProperty() koja će nam vratiti
interpretaciju neke funkcionalnosti vezane za operativni sistem ili program. Na primer ako znati
putanje u UNIX baziranim operativnim sistemima idu kao /home/korisnik/etc dok u windowsu
C:\users\korisnik. Treba primetiti da za jedan OS je putanja sa / a za drugi sa \. System.getProperty()
može za nas da kreira taj separator da bi bili sigurni da naša aplikacija radi nezavisno od platforme.
Primer bi bio System.getProperty("file.separator") + "do" + System.getProperty("file.separator") gde
je svojstvo file.separator ono koje obezbeđuje da se razlikuje da li je UNIX ili Windows baziran sistem.
Isto tako i line.separator će adaptirati kako da se upiše novi red u zavisnosti od tipa fajla.
Druga stvar je StandardOpenOption enumerator koji nam daje neke mogućnosti sa našim fajlom
između ostalog WRITE i APPEND opcije za pisanje u datoteku. Važno: WRITE će samo dodati novi
sadržaj na početak. Ako je taj sadržaj manji od starog, ostatak starog sadržaja ostaće posle novog.
Da bi se ovo izbeglo koristi se opcija TRUNCATE_EXISTING koja će obrisati sadržaj u datoteci.
Drugi način je korišćenjem klasa PrintWriter i FileWriter. FileWriter otvara tok ka fajlu u koji želimo da
upišemo sadržaj, dok PrintWriter zapravo nam omogućava da upišemo sadržaj. Kod je sledeći:
try {
FileWriter fw = new FileWriter("test.txt", false);
PrintWriter out = new PrintWriter(fw);
out.print("Neki string koji želimo da upišemo" +
System.getProperty("line.separator") + "Ima i više redova");
out.close();
fw.close();
} catch (IOException ex) {
System.err.println(ex);
}
U konstruktoru FileWriter-a stoji false, ovo znači da želimo da obrišemo stari sadržaj. Ako je stavljeno
false onda se briše stari sadržaj i dodaje novi na početak, a ako je true dodaje se sadržaj na kraj fajla.
Korišćenjem metode print možemo da upišemo sadržaj.

You might also like