6. PRÁCE S DATOVÝMI PROUDY Balík java.io obsahuje třídy, které slouží pro zpracování datových výstupů a vstupů. Pro obvyklou práci se soubory zde můžeme najít třídy File a RandomAccessFile. Většina tříd se však věnuje práci s datovými proudy. A to jak binárními jejichž hlavní zastánci jsou třídy OutputStream a InputStream, tak i znakovými jejichž hlavní třídy jsou Writer a Reader. Od hlavních tříd je pak odvozena řada potomků, kteří se specializují na určité datové proudy, například balík java.util.zip obsahuje proudy pro práci s komprimovanými daty. V následujících podkapitolách můžete najít stručný popis hlavních tříd s některými jejich metodami, pro přehlednost nejsou uvedeny deklarované výjimky jednotlivých metod.
TŘÍDA FILE Třída File umožňuje nezávisle na platformě definovat názvy souborů a adresářů. Dále nabízí metody pro ověření existence, možnosti přístupu (čtení/zápis), výpis souboru v adresáři, vytváření adresářů, přejmenování adresářů/souborů a jejich mazání.
public boolean exist() - test zda soubor/adresář existuje, public boolean isDirectory() - test na adresář, public boolean isFile() - test na soubor, public boolean canRead() - test na čtení souboru, public boolean canWrite() - test na zápis do souboru, public String getName() - vrací jméno souboru zbavené jmen adresářů, public String getPath() - vrací jméno souboru s kompletní cestou, public String getParent() - vrací kompletní cestu k souboru, public long length() - vrací délku souboru, public boolean mkdir() - vytvoří adresář, public boolean mkdirs() - vytvoří adresář i s podadresáři, public boolean delete() - smaže soubor/adresář, public boolean renameTo(File cíl) - přejmenuje soubor, public String[] list() - zjistí všechny soubory/adresáře odpovídající zadanému jménu při vytvoření objektu.
Příklad: File soubor = new File("soubor.txt"); System.out.println("Délka souboru: " + soubor.length());
TŘÍDA RANDOMACCESSFILE Tato třída umožňuje náhodný přístup k souboru a práci s ním. Otevření souboru se provede při vytváření objektu konstruktorem. Ve třídě RandomAccessFile jsou definovány dva veřejné konstruktory: public RandomAccessFile(String soubor, String mód); public RandomAccessFile(File soubor, String mód); Parametr mód může být buď "r" pro otevření souboru jen pro čtení, nebo "rw" pro otevření souboru pro zápis i čtení. Po otevření souboru je vždy nastaveno ukazovátko na začátek souboru, a to v obou módech. Ani jeden mód neruší obsah souboru.
public native long getFilePointer() - vrací aktuální pozici v souboru, public native long length() - zjistí délku souboru, public native void seek(long poz) - nastaví pozici v souboru na poz, public native void close() - zavře soubor, public native int read() - načte jeden byte, public int read(byte b[]) - načte b.length bytů, public final boolean readBoolean(), byte readByte(), char readChar(), ... - načte primitivní datový typ, public final String readLine() - načte řetězec v Unicode, public final String readUTF() - načte řetězec v UTF kódování, public native void write(int b) - zapíše byte(!), public void write(byte b[]) - zapíše b.length bytů, public final void writeBoolean(boolean v), void writeByte(byte v), void writeChar(char v), ... - zapíše primitivní datový typ, public final void writeBytes(String s) - zapíše řetězec jako sled bytů, public final void writeChars(String s) - zapíše řetězec jako sled znaků, public final void writeUTF(String s) - zapíše řetězec v kódování UTF.
Příklad: import java.io.*; public class KopirovaniSouboru { public static void main(String[] argv) throws IOException
{
if (argv.length != 2) return; File soubor1 = new File(argv[0]); File soubor2 = new File(argv[1]); if (!soubor1.isFile()) return; if (soubor2.exists()) soubor2.delete(); RandomAccessFile zdroj = new RandomAccessFile(soubor1,"r"); RandomAccessFile cil
= new RandomAccessFile(soubor2,"rw");
for (int n = 0; n < soubor1.length(); n++) cil.writeByte(zdroj.readByte()); zdroj.close(); cil.close(); } }
TŘÍDA INPUTSTREAM Abstraktní třída InputStream je rodičovskou třídou všech vstupních bytových datových proudů. Definuje základní metody pro jejich zpracování.
public InputStream() - veřejný konstruktor, public abstract int read() - načte byte, public int read(byte b[]) - načte b.length bytů, public void close() - zavře vstupní datový proud, public long skip(long n) - přeskočí n bytů na vstupu, public boolean markSupported() - vrací true pokud vstupní datový proud podporuje "značkování", public synchronized void mark(int limit) - nastaví značku v datovém proudu, public synchronized void reset() - vrací se zpět na značku. Metodou mark() si lze označit aktuální pozici ve vstupním proudu a metodou reset() se lze pak na tuto pozici vrátit. Pokud přesáhne počet načtených bytů hodnotu, kterou udává parametr limit metody mark, je značka zrušena. Tyto dvě metody lze však použít pouze tehdy, vrátí-li metoda markSupported() hodnotu true. Od abstraktní třídy InputStream jsou pak odvozeny například třídy:
FileInputStream - umožňuje přístup k souborům na nízké úrovni, proto je používaná pro vlastní čtení metodami jiných tříd, například třídou DataInputStream. FilterInputStream - poskytuje metody, které lze použít pro filtrování dat ze vstupního proudu. Vlastní filtrování však provádí její potomci. Mezi ně patří např. již zmiňovaná třída DataInputStream. PipedInputStream - slouží k vytvoření roury pro komunikaci mezi vlákny.
TŘÍDA OUTPUTSTREAM OutputStream je abstraktní třída definující metody pro bytový výstupní proud. Je rodičovskou třídou všech výstupních proudů.
public public public public public
OutputStream() - veřejný konstruktor, abstract void write(int b) - zapíše byte(!), void write(byte b[]) - zapíše b.length bytů, void flush() - vyprázdní výstupní vyrovnávací paměť, void close() - zavře datový proud.
Mezi potomky třídy OutputStream patří např. FilterOutputStream, FileOutputStream či PipedOutputStream. Tyto třídy jsou obdobou tříd odvozených od třídy InputStream.
TŘÍDA READER Reader je abstraktní třída definující metody všech znakově orientovaných vstupních datových proudů.
public boolean ready() - zjistí, zda je k dispozici další znak, public int read() - načte jeden znak, public int read(char c[]) - načte c.length znaků, public abstract void close() - zavře vstupní datový proud, public long skip(long n) - přeskočí (ignoruje) n znaků na vstupu, public boolean markSupported() - vrací true pokud vstupní datový proud podporuje "značkování", public void mark(int limit) - nastaví značku v datovém proudu, public void reset() - vrací se zpět na značku.
Funkce metod je obdobná jako u třídy InputStream.
TŘÍDA WRITER Writer je abstraktní třída definující metody všech znakově orientovaných výstupních datových proudů.
public void write(int c) - zapíše jeden znak, public void write(char c[]) - zapíše c.length znaků, public void write(String s) - zapíše řetězec, void flush() - vyprázdní výstupní vyrovnávací paměť, public abstract void close() - zavře datový proud.
Funkce metod je obdobná jako u třídy OutputStream. Příklad: import java.io.*; public class KopirovaniProudu { public static void main(String[] argv) throws IOException
{
if(argv.length != 2) return; File soubor1 = new File(argv[0]); File soubor2 = new File(argv[1]); if(!soubor1.isFile()) return; if(soubor2.exists()) soubor2.delete(); FileInputStream zdroj = new FileInputStream(soubor1); FileOutputStream cil
= new FileOutputStream(soubor2);
for(int n = 0; n < soubor1.length(); n++) cil.write(zdroj.read()); zdroj.close(); cil.close(); } }
STANDARDNÍ VSTUP A VÝSTUP Standardní vstup a výstup je definován v třídě java.lang.System. V této třídě je definován i standardní chybový výstup. Standardní vstup je označen identifikátorem in a je to instance třídy InputStream. Oba výstupy jsou instancemi třídy PrintStream, která je odvozena od třídy
FilterOutputStream. Standardní výstup je označen identifikátorem out, chybový výstup pak identifikátorem err. Třída PrintStream nabízí statické metody: print( parametr ) println( parametr ) kde parametr může být prázdný nebo některý z primitivních datových typů boolean, char, double, float, int, long a samozřejmě String. Příklad: System.out.print("Pěkný den!"); System.out.println(1011); System.out.println();
// odřádkuje
Čtení z klávesnice je poněkud komplikovanější, jelikož abstraktní třída InputStream nabízí jen metodu read() pro načtení jednoho bytu ze vstupu. Příklad: Načtení řetězce o max. délce 30 znaků z klávesnice může vypadat takto: byte pole[] = new byte[30];
// (1)
System.in.read(pole);
// (2)
String text = new String(pole);
// (3)
System.out.println("Byl zadan: " + text);
// (4)
Na řádce (1) je deklarováno bytové pole, do kterého je následně načten vstup metodou read (2). Maximální délka vstupu je omezena hodnotou pole.length. Vstup se ukončí klávesou ENTER. Pokud je vstup delší je automaticky oříznut. Jelikož však vstup z klávesnice umožňuje vstup znaků v ASCII kódu je nutné provést převod na Unicode. Na řádce (3) je k tomuto účelu použít konstruktor třídy String, který převede bytové pole na řetězec. Z tohoto je zřejmé, že tento převod lze použít pro znaky 0-127 ASCII tabulky (viz příloha C.). Poslední řádka (4) pak načtený výsledek zobrazí.