Vaše jistota na trhu IT Copyright © 2008, Rudolf Pecinovský 1 Soubory a proudy Rudolf Pecinovský
Vaše jistota na trhu IT Copyright © 2008, Rudolf Pecinovský2 Koncepce čtení a ukládání dat
Copyright © 2008, Rudolf Pecinovský 3 Terminologie ►Soubor Entita (objekt) operačního systému sloužící jako obálka pro úschovu dat ►Datový proud Objekt programu sloužící ke zprostředkování přenosu dat mezi zdrojem a cílem ● Program může být zdrojem, cílem, či obojím ►Serializovatelnost Schopnost objektu být odeslán datovým proudem a zrekonstruovat se po přijetí zpět na plnohodnotný objekt ►Persistence Schopnost objektu uchovat svůj stav mezi dvěma seancemi
Copyright © 2008, Rudolf Pecinovský 4 Koncepce ►Java odděluje práci se soubory od práce s jejich obsahem a do jisté míry i od vlastní serializace ►Práce se soubory: ● Vytvoření, přesun, přejmenování, odstranění, … ● Zjištění názvu, velikosti, přístupových práv, … ►Práce s obsahem ● Otevření proudu ● Čtení a zápis dat ● Spláchnutí (flush) a zavření proudu ►Serializace ● Ukládání objektů a jejich rekonstrukce po opětném načtení včetně případných odkazů ● Řešení problémů s citlivými či zbytečně ukládanými daty ● Řešení problémů verzemi tříd ● Řešení problémů s objekty kontrolujícími vytváření svých instanci
Copyright © 2008, Rudolf Pecinovský 5 Historie ►Na počátku byla v balíčku java.io definována práce se soubory a s proudy bajtů ►Koncepce proudů založena na vzoru Dekorátor ►Při práci s proudy znaků v národních abecedách problémy => ve verzi 1.2 zavedeny znakové proudy ►Pro zvýšení efektivity nízkoúrovňových blokových operací byl ve verzi 1.4 přidán balíček java.nio ( n ew i nput o utput) ● Po přidání toho balíčku byly původní proudy z java.io upraveny tak, aby jej využívaly => nevyžadujeme-li zvýšenou efektivitu a škálovatelnost, není třeba měnit kód ►Ve verzi 7 byl přidán balíček java.nio.file s dalšími rozšířeními a zefektivněním práce s velkými soubory
Vaše jistota na trhu IT Copyright © 2008, Rudolf Pecinovský6 Práce se soubory – třída java.io.File
Copyright © 2008, Rudolf Pecinovský 7 Charakteristika třídy File 1/2 ►Neměnný hodnotový typ ►Abstraktní reprezentace cesty k souboru či složce ● Nereprezentuje soubor, ale jeho název ►Díky abstrakci umožňuje definovat práci se soubory a složkami nezávisle na platformě a jejích specifikách ● Je schopna se přizpůsobit různým oddělovačům souborů na cestě ( / versus \ ) a cest v seznamu ( : versus ; ) ● Je schopna jednotně zacházet s různými přístupy ke kořenovým složkám ● Je schopna se vypořádat s různými interpretacemi vlivu velikosti znaků na vlastní cestu ● Umí správně reagovat na zadání relativní i absolutní cesty
Copyright © 2008, Rudolf Pecinovský 8 Charakteristika třídy File 2/2 ►Instance třídy File reprezentuje jak soubor, tak složku ● O koho se konkrétně jedná zjistíme až dotazem ►Instance může reprezentovat i neexistující soubor ● Zda existuje zjistíme dotazem ►Dotazy na reálné soubory a jejich vlastnosti jsou hlídány bezpečnostním správcem (security manager)
Copyright © 2008, Rudolf Pecinovský 9 Konstruktory a tovární metody ►Konstruktory ● File(String pathname) ● File(String parent, String child) ● File(File parent, String child) ● File(URI uri) ►Statické tovární metody ● createTempFile(String prefix, String suffix) ● createTempFile(String prefix, String suffix, File directory) ● File[] listRoots() ►Převody ● URI toURI() ● URL toURL() Deprecated – NEPOUŽÍVAT, Místo toho vytvořit URI a ten pak převést metodou toURL()
Copyright © 2008, Rudolf Pecinovský 10 Relativní – absolutní – kanonická cesta ►Cesty (String) ● String getName() ● String getParent() ● String getPath() ● String toString() ● String getAbsolutePath() ● String getCanonicalPath() ►Soubory ● File getParentFile() ● File getAbsoluteFile() ● File getCanonicalFile() ►Dotazy ● boolean isAbsolute() ►Kanonická cesta zaručuje, že instance reprezentující shodnou kanonickou cestu odkazují na týž soubor
Copyright © 2008, Rudolf Pecinovský 11 Soubory × složky ►Dotazy ● boolean isDirectory() ● boolean isFile() ● boolean isHidden() ►Obsah složky – názvy ● String[] list() ● String[] list(FilenameFilter filter) ►Obsah složky – soubory ● File[] listFiles() ● File[] listFiles(FileFilter filter) ● File[] listFiles(FilenameFilter filter ) ►Rozhraní FileFilter ● boolean accept(File pathname) ►Rozhraní FileNameFilter ● boolean accept(File dir, String name)
Copyright © 2008, Rudolf Pecinovský 12 Vlastnosti souboru ►Povolené čtení ● boolean canRead() ● boolean setReadable(boolean readable) ● boolean setReadable(boolean readable, boolean ownerOnly) ►Povolený zápis ● boolean canWrite() ● boolean setReadOnly() ● boolean setWritable(boolean writable) ● boolean setWritable(boolean writable, boolean ownerOnly) ►Povolené spuštění programu v souboru ● boolean canExecute() ● boolean setExecutable(boolean executable) ● boolean setExecutable(boolean execut, boolean ownerOnly) ►Čas poslední modifikace ● long lastModified() ● boolean setLastModified(long time) ►Další vlastnosti ● long length() ● boolean isHidden()
Copyright © 2008, Rudolf Pecinovský 13 Práce se soubory na disku ►Zjištění existence souboru ● boolean exists() ►Vytvoření souboru ● boolean mkdir() Vytvoří novou podsložku v existující rodičovské složce ● boolean mkdirs() Vytvoří novou podsložku včetně potřebných rodičovských složek ● boolean createNewFile() ►Mazání souboru ● boolean delete() Smaže soubor ihned ● void deleteOnExit() Smaže soubor při ukončení programu ►Přejmenování souboru ● boolean renameTo(File dest)
Spouštění aplikací operačního systému ►Soubory můžeme číst či zapisovat, ale také je můžeme spouštět ►Máme-li soubor asociovaný s nějakou aplikací aktuálního operačního systému, můžeme jej spustit sekvencí (používáme třídu java.awt.Desktop ): Copyright © 2008, Rudolf Pecinovský 14 Desktop desktop = Desktop.getDesktop(); try { desktop.open(file); } catch (IOException ex) { throw new RutimeException( "Soubor " + file + " se nepodařilo spustit"); }
Copyright © 2008, Rudolf Pecinovský 15 Zjišťování souboru ve složce třídy ►Je-li soubor ve stejné složce jako class-soubor dané třídy, mohu jej vyhledat prostřednictvím class-objektu ● URL getResource(String name) ● InputStream getResourceAsStream(String name) ►Odvozujeme-li umístění souboru od složky s kořenovým balíčkem, využijeme ClassLoader – ten nabízí stejně metody, jen začíná v kořenovém balíčku ►Zadáním prázdného řetězce obdržíme URL složky s danou třídou, resp. s kořenovým balíčkem ►Tímto způsobem můžeme přistupovat i k obsahu souborů, které jsou součástí JAR ● V JARu nemůžeme pracovat se soubory, ale pouze s jejich obsahem ● Soubory v JARu můžeme číst, ale nemůžeme do nich zapisovat ● U názvů souborů v JARu VŽDY ZÁLEŽÍ na velikosti písmen
Copyright © 2008, Rudolf Pecinovský 16 Třída Soubor 1/5 import java.io.File; import java.net.URL; import java.net.URI; import java.net.URISyntaxException; /******************************************************************** * Knihovní třída Soubor} definuje metody usnadňující získání * instancí třídy File} reprezentujících požadovaný soubor. * Rudolf PECINOVSKÝ */ public class Soubor { //== KONSTRUKTORY A TOVÁRNÍ METODY ================================== /** Soukromý konstruktor bránící vytvoření instancí. */ private Soubor() {}
Copyright © 2008, Rudolf Pecinovský 17 Soubor. getFile(String, Object) 2/5 /********************************************************************* * Vrátí soubor se zadaným názvem zadaným vůči složce, * v níž je umístěn class-soubor zadané instance. * název Název požadovaného souboru instance Instance třídy, v jejíž složce se soubor nachází, * resp. odkud začíná jeho relativní adresa Instance třídy File} * reprezentující požadovaný soubor */ public static File getFile(String název, Object instance) { Class classObjekt = instance.getClass(); return getFile(název, classObjekt); }
Copyright © 2008, Rudolf Pecinovský 18 Soubor.getFile(String, Class ) 3/5 /********************************************************************* * Vrátí soubor se zadaným názvem zadaným vůči složce, * v níž je umístěn zadaný class-soubor. * název Název požadovaného souboru cls Class-objekt třídy, v jejíž složce se soubor nachází, * resp. odkud začíná jeho relativní adresa Instance třídy File} * reprezentující požadovaný soubor */ public static File getFile(String název, Class cls) { URL url = cls.getResource(název); if (url == null) { throw new IllegalArgumentException( String.format( "\nNebyl nalezen soubor \"%s\" ve složce \"%s\"", název, cls.getResource("") ) ); } return url2file(url); }
Copyright © 2008, Rudolf Pecinovský 19 Soubor.getFile(String) 4/5 /************************************************************* * Vrátí soubor se zadaným názvem * zadaným vůči složce s kořenovým balíčkem. * název Název požadovaného souboru Instance třídy File} * reprezentující požadovaný soubor */ public static File getFile(String název) { ClassLoader clsLdr = Soubor.class.getClassLoader(); URL url = clsLdr.getResource(název); if (url == null) { throw new IllegalArgumentException( String.format( "\nNebyl nalezen soubor \"%s\" ve složce \"%s\"", název, clsLdr.getResource("") ) ); } return url2file(url); }
Copyright © 2008, Rudolf Pecinovský 20 Soubor.url2file(URL) 5/5 public static File url2file(URL url) { URI uri; try { uri = url.toURI(); }catch( URISyntaxException use ) { throw new RuntimeException( "\nZadané URL nelze konvertovat na URI", use); } File file; try { file = new File(uri); }catch( Exception e ) { String jar = uri.toString().startsWith("jar:") ? "\nHledaný soubor se nachází v souboru JAR" : ""; String s = "\nURI: " + uri + "\nnelze konvertovat na File; " + jar; throw new RuntimeException( s, e); } return file; }
Vaše jistota na trhu IT Copyright © 2008, Rudolf Pecinovský21 Třída javax.swing.JFilechooser
Copyright © 2008, Rudolf Pecinovský 22 javax.swing.JFileChooser ►Umožňuje ● Vybrat více souborů současně ● Zadat, zda se má vybírat soubor, složka, či oboje ● Definovat filtry pro zobrazení vybraných typů souborů ● Zabudovat do dialogového okna náhled či jinou komponentu ● Začlenit okno jako komponentu do větších celků
Copyright © 2008, Rudolf Pecinovský 23 Postup pro otevření souboru1/4 1.Vytvoření instance třídy JFileChooser ● Vytvořenou instanci je výhodné používat vícekrát, neboť její vytvoření trvá relativně dlouho (zjišťují se dostupné diskové jednotky) ● Konstruktory: JFileChooser() JFileChooser(File currentDirectory) JFileChooser(String currentDirectoryPath) ●Bez parametru nebo s parametrem null začáíná v uživatelově implicitním adresáři 2.Nastavení počáteční složky pro vyhledávání pomocí setCurrentDirectory(File) 3.Přednastavení jména souboru pomocí metody setSelectedFile(File) 4.Potřebujeme-li umožnit vybrat více souborů současně, zavoláme setMultipleSelectionEnabled(boolean)
Copyright © 2008, Rudolf Pecinovský 24 Postup pro otevření souboru2/4 5.Nastavit filtry (masky) pro výběr souborů (např. pouze soubory *.txt) jako instance třídy javax.swing.filechooser.FileFilter ● Třída vyžaduje implementaci abstraktních metod ● boolean accept(File f) Vrací true, má-li se daný soubor nabízet ● String getDescription() Vrací popis filtru, podle nějž jej uživatel vybírá ● Java 6.0 zavedla předdefinovanou třídu FileNameExtensionFilter ●Té se zadá popis následovaný jednotlivými příponami FileNameExtensionFilter(String desc, String... ext) ● Filtrů může být více, přidávají se voláním void addChoosableFileFilter(FileFilter)
Copyright © 2008, Rudolf Pecinovský 25 Postup pro otevření souboru3/4 6.Zavoláním setFileSelectionMode(int) zadat, zda se mají vybírat adresáře a/nebo soubory ● JFileChooser.FILES_ONLY ● JFileChooser.DIRECTORIES_ONLY ● JFileChooser.FILES_AND_DIRECTORIES 7.Zobrazit dialogové okno pro výběr souborů či složek zavoláním metody ● showOpenDialog(Component parent) ● showSaveDialog(Component parent) ● showDialog(Component parent, String approveButtonText) Chceme-li sami zadat text na potvrzovacím tlačítku
Copyright © 2008, Rudolf Pecinovský 26 Postup pro otevření souboru4/4 8.Předchozí metody vracejí jednu ze dvou konstant ● JFileChooser.APPROVE_OPTION ● JFileChooser.CANCEL_OPTION 9.Vybraný(-né) soubor(y) získáme zavoláním ● File getSelectedFile() ● File[] getSelectedFiles() ►Existuje ještě plejáda dalších možností použití
Vaše jistota na trhu IT Copyright © 2008, Rudolf Pecinovský27 Třída javafx.stage.FileChooser
Copyright © 2008, Rudolf Pecinovský 28 Mac0S – Linux – Windows
Copyright © 2008, Rudolf Pecinovský 29 Postup pro otevření / uložení souboru1/4 1.Vytvoření instance třídy: new FileChooser() ● Vytvořenou instanci je výhodné používat vícekrát, neboť její vytvoření trvá relativně dlouho (zjišťují se dostupné diskové jednotky) 2.Nastavení titulku okna pomocí metody void setTitle(String value) 3.Nastavení počáteční složky pro vyhledávání pomocí metody void setInitialDirectory(File value) 4.Přednastavení jména souboru pomocí metody void setInitialFileName(String value) 5.Nastavení podmnožiny souborů. z nichž budeme vybírat void setSelectedExtensionFilter( FileChooser.ExtensionFilter filter)
Copyright © 2008, Rudolf Pecinovský 30 Postup pro otevření / uložení souboru 2/4 5.Nastavit filtry (masky) pro výběr souborů (např. pouze soubory *.txt) prostřednictvím volání metody void setSelectedExtensionFilter( FileChooser.ExtensionFilter filter) ● Třída FileChooser.ExtensionFilter je definována jako interní (vnořená) přepravka; definuje konstruktory: ● ExtensionFilter(String description, List extensions)) ● ExtensionFilter(String description, String... extensions) ● Její instance definují metody: ● String getDescription() ● List getExtensions()
Copyright © 2008, Rudolf Pecinovský 31 Postup pro otevření / uložení souboru 3/4 6.Otevřít dialogové okno a provést požadovanou akci ● File showOpenDialog(Window ownerWindow) Uživatel nastaví jeden vstupní soubor ● List showOpenMultipleDialog(Window ownerWindow) Uživatel může nastavit otevření více vstupních souborů současně ● File showSaveDialog(Window ownerWindow) Okno pro nastavení výstupního souboru ►Třída FileChooser definuje FX-vlastnosti ● ObjectProperty initialDirectoryProperty ● ObjectProperty initialFileNameProperty ● ObjectProperty selectedExtensionFilterProperty ● Tyto vlastnosti můžeme využívat tak, jak je v JavaFX zvykem
Vaše jistota na trhu IT Copyright © 2008, Rudolf Pecinovský32 Návrhový vzor Adaptér
Copyright © 2008, Rudolf Pecinovský 33 Motivace ►Občas potřebujeme, aby třída měla jiné rozhraní než to, které má ● Třída neimplementuje požadované rozhraní, nicméně poskytuje požadovanou funkčnost ● Příklad: používáme třídu z jedné knihovny, jejíž instance bychom mohli použít jako parametry metod jiné knihovny, ale tato jiná knihovna vyžaduje parametry implementující nějaké specifické rozhraní, které naše třída nezná ►Dopředu víme, že z hlediska požadované funkčnosti stačí implementovat pouze část daného rozhraní nicméně překladač vyžaduje kompletní implementaci ● Iterátor neumožňující odstraňovat prvky z kontejneru ● Kontejnery s předem zadaným, nezměnitelným obsahem ● Posluchači některých událostí při tvorbě GUI
Copyright © 2008, Rudolf Pecinovský 34 Adaptér jako rodič adaptované třídy ►Třída Adaptér definuje implicitní implementace všech metod požadovaných rozhraním IPožadované přičemž implicitní verze typicky: ● Vyhazuje UnsupportedOperationException ● Nedělá nic ►Potomci pak mohou definovat pouze ty metody, které se jim „hodí do krámu“ ►Pro klienta potomek implementuje vše
Copyright © 2008, Rudolf Pecinovský 35 Příklad – adaptér jako předek public interface IPosuvný extends IKreslený { //== DEKLAROVANÉ METODY ================================= public Pozice getPozice(); public void setPozice( Pozice pozice ); public void setPozice( int x, int y ); //== VNOŘENÉ TŘÍDY ====================================== public static class Adaptér extends IKreslený.Adaptér implements IPosuvný { public Pozice getPozice(){ throw new UnsupportedOperationException(); } public void setPozice( int x, int y ) { throw new UnsupportedOperationException(); } public void setPozice( Pozice pozice ) { setPozice( pozice.x, pozice.y ); } Metoda s definovatelnou implementací používající vzor Šablonová metoda Metody, o jejichž implementaci se uživatel může rozhodnout podle potřeby Adaptér je definován jako třída vnořená do rozhraní, na něž bude své potomky adaptovat
Copyright © 2008, Rudolf Pecinovský 36 Adaptovaný objekt jako atribut1/2 ►Adaptér definuje atribut s odkazem na adaptovaný objekt public class Adaptér implements IPožadované { Existující adaptovaný; public Adaptér(Existující exist) { adaptovaný = exist; }
Copyright © 2008, Rudolf Pecinovský 37 Adaptovaný objekt jako atribut2/2 ►Všechna volání metod „přehrává“ na volání ekvivalentních metod adaptovaného objektu public class Adaptér implements IPožadované { Existující adaptovaný; public Adaptér(Existující exist) { adaptovaný = exist; } public void metoda(Parametr parametr) { Požadovaný požadovaný = uprav(parametr); adaptovaný.jehoMetoda(požadovaný); }
Vaše jistota na trhu IT Copyright © 2008, Rudolf Pecinovský38 Návrhový vzor Dekorátor
Copyright © 2008, Rudolf Pecinovský 39 Motivace ►V knihovně potřebujeme nabízet třídy‘ poskytující různé kombinace funkcionalit ►Při nutnosti nabízet téměř všechny možné kombinace roste počet potřebných tříd kombinatoricky = neúnosně ►S každou další přidanou funkcionalitou musíme přidat násobek dosud existujících tříd ►S každou přidanou základní třídou musíme přidat i třídy pro možné kombinace přidaných funkcionalit
Copyright © 2008, Rudolf Pecinovský 40 Řešení ►Využít postupu aplikovaného u návrhového vzoru Adaptér a zabalit objekt do objektu poskytujícího novou funkcionalitu, který tak původní objekt ozdobí (dekoruje) novou funkcionalitou ►Pro každou novou funkcionalitu pak bude stačit přidat pouze jedinou obalovou (dekorující) třídu ►Přidávané funkcionality je možné kumulovat, tj. zabalený objekt lze znovu zabalit do objektu přidávajícího další funkcionalitu ● Výsledný objekt lze vytvářet postupně: AAuto benzin = new Benzin(); AAuto abs = new ABS( benzin ); AAuto auto = new Automat(abs); ● Nebo najednou AAuto auto = new Automat( new ABS(new Benzin()) );
Copyright © 2008, Rudolf Pecinovský 41 Využití adaptéru ►Pro všechny dekorující třídy lze definovat společného rodiče, který volání neupravených metod převede na volání odpovídajících metod dekorovaného objektu ►Každá nově přidaná základní třída automaticky získává všechny v úvahu přicházející funkcionality
Copyright © 2008, Rudolf Pecinovský 42 Společný rodič dekorujících tříd public class Dekorovaný extends AAuto { AAuto dekorovaný; public Dekorovaný(AAuto auto) { dekorovaný = auto; } public void zrychliNa(int rychlost, int doba) { dekorovaný.zrychliNa( rychlost, doba ); } public void zpomalNa(int rychlost, int dráha) { dekorovaný.zpomalNa( rychlost, dráha ); } public void zabrzdiNa(int dráha) { dekorovaný.zabrzdiNa( dráha ); }
Vaše jistota na trhu IT Copyright © 2008, Rudolf Pecinovský43 Čtení a zápis dat pomocí proudů
Copyright © 2008, Rudolf Pecinovský 44 Charakteristika ►Koncepce převzatá z C/C++ (1984) ►Datový proud je objekt zabezpečující tok dat mezi zdrojem a cílem ►Alespoň na jednom konci proudu musí být program ►Proudy umožňují jednotnou práci s daty nezávisle na jejich zdroji, cíli a a doprovodných akcích (používání vyrovnávací paměti, filtrování nezajímavých dat, šifrování, bezpečnostní kontroly, formátování …)
Copyright © 2008, Rudolf Pecinovský 45 Skupiny proudů ►V každé skupině jsou pak proudy lišící se podle zdroje/cíle ● Z/do souboru ● Z/do pole/objektu ● Z/do programu ● … java.io BajtovéZnakové Vstupní InputStreamReader Výstupní OutputStreamWriter
Copyright © 2008, Rudolf Pecinovský 46 Další možnosti ►Proudy mohou poskytovat dodatečnou funkčnost ● Používání vyrovnávací paměti (buffer) ● Čtení s možností vrácení přečtených znaků ● Převod dat do binárního tvaru a zpět ● Ukládání a načítání objektů (serializace) ● Komprimace a dekomprimace dat ● Šifrování a dešifrování ● … ►Proudy poskytující další funkčnost jsou definovány aplikací návrhového vzoru Dekorátor
Copyright © 2008, Rudolf Pecinovský 47 Přehled vstupních bajtových proudů ► InputStream ● ByteArrayInputStream – proud pro čtení z pole bajtů ● FileInputStream – proud pro čtení ze souboru ● FilterInputStream – univerzální rodič pro vstupní bajtové proudy s dodatečnou funkčností (společných rodič některých dekorátorů) ● BufferedInputStream – proud pro čtení s vyrovnávací pamětí ● DataInputStream – proud pro čtení hodnot primitivních typů a řetězců ● LineNumberInputStream ● PushBackInputStream – vstupní proud umožňující návrat a opětovné čtení ● ObjectInputStream – proud pro čtení serializovaných objektů ● PipedInputStream – proud pro čtení z „datovodu“ (trubky – pipe), do nějž zapisuje jiná část programu nebo jiný program. ● SequenceInputStream – zřetězení vstupních proudů ● StringBufferInputStream
Copyright © 2008, Rudolf Pecinovský 48 Přehled vstupních znakových proudů ► Reader ● BufferedReader – vstupní znakový proud využívající vyrovnávací paměť ● LineNumberReader – proud, který navíc umí pracovat s čísly řádků ● CharArrayReader – proud pro čtení z pole znaků ● FilterReader – univerzální rodič pro vstupní znakové proudy s dodatečnou funkčností (společných rodič některých dekorátorů) ● PushBackReader –proud umožňující návrat a opětovné čtení ● InputStreamReader – převaděč bajtového proudu na znakový ● FileReader – proud pro čtení ze souboru ● PipedReader – proud pro čtení z „datovodu“ (trubky – pipe), do nějž zapsal jiný modul či program ● StringReader – proud pro čtení z textového řetězce (stringu)
Copyright © 2008, Rudolf Pecinovský 49 Přehled výstupních bajtových proudů ► OutputStream ● ByteArrayOutputStream – proud pro zápis do pole bajtů ● FileOutputStream – proud pro zápis do souboru ● FilterOutputStream – univerzální rodič pro výstupní bajtové proudy s dodatečnou funkčností (společných rodič některých dekorátorů) ● BufferedOutputStream – proud využívající vyrovnávací paměť ● DataOutputStream – proud pro zápis hodnot primitivních typů a řetězců ● PrintStream – výstupní bajtový proud určený k tisku na výstupní zařízení ● ObjectOutputStream – výstupní bajtový proud schopný serializovat (uložit, odeslat, …) instance objektových typů ● PipedOutputStream – výstupní bajtový proud odesílající data prostřednictvím „datovodu“ (trubky – pipe) do jiného modulu či programu
Copyright © 2008, Rudolf Pecinovský 50 Přehled výstupních znakových proudů ► Writer ● BufferedWriter – výstupní znakový proud využívající vyrovnávací paměť ● CharArrayWriter – znakový proud zapisující do pole znaků ● FilterWriter – univerzální rodič pro výstupní znakové proudy s dodatečnou funkčností (společných rodič budoucích dekorátorů) ● OutputStreamWriter – proud převádějící bajtový proud na znakový ● FileWriter – výstupní znakový proud zapisující do souboru ● PipedWriter – výstupní znakový proud odesílající data prostřednictvím „datovodu“ (trubky – pipe) do jiného modulu či programu ● PrintWriter – znakový proud určený k tisku na výstupní zařízení ● StringWriter – znakový proud zapisující do textového řetězce
Copyright © 2008, Rudolf Pecinovský 51 Pomocná rozhraní ► FileFilter Filtrování souborů podle vlastností (název, délka, soubor/složka, …) ► FilenameFilter Filtrování souborů podle názvu ► DataInput Proudy schopné číst řetězce a hodnoty primitivních typů ► ObjectInput Proudy schopné číst (deserializovat) instance objektových typů ► Serializable Značkovací rozhraní implementované třídami, jejichž instance lze serializovat a deserializovat ► Flushable Objekty, které je možné „spláchnout“ příkazem flush() ► Closeable Objekty, které je možné zavřít příkazem close() ► DataOutput Proudy shopné odesílat řetězce a hodnoty primitivních typů ► ObjectOutput Proudy schopné odesílat (serializovat) instance objektových typů ► Externalizable Rozhraní pro alternativní způsob serializace/deserializace
Copyright © 2008, Rudolf Pecinovský 52 Společné charakteristiky ►Konstruktor proud současně také otevírá => instance proudu má smysl vytvářet až v okamžiku, kdy daný proud doopravdy potřebuji (jinak proud zbytečně blokuje zdroje) ►Při ukončení práce musím proud zavřít ● Všechny proudy implementují rozhraní Closeable, takže je pro ně možné vytvořit společnou zavírací metodu, které bude jednotným způsobem řešit případné problémy ►Chceme-li mít při použití výstupních proudů zaručeno, že data doopravdy odešla na výstupní zařízení (a neflákají se ve vyrovnávací paměti), musíme data spláchnout zavoláním metody flush() ● Všechny výstupní proudy implementují rozhraní Flushable, takže je pro ně možné vytvořit společnou zavírací metodu, které bude jednotným způsobem řešit případné problémy
Copyright © 2008, Rudolf Pecinovský 53 Metody vstupních proudů1/3 ►Stream: int available() ● Vrátí počet bajtů, které ještě mohou být přečteny nebo přeskočeny. ►Reader: boolean ready() ● Je-li možno přečíst další znaky bez čekání, vrátí true. Vrátí-li false, ještě to neznamená, že se při dalším čtení zablokuje, protože se mezi tím mohou nějaké znaky na vstupu objevit. Nicméně v okamžiku testování na vstupu zrovna nic není. ►Stream: int read() Reader: int read() ● Přečte ze vstupu další bajt, resp. znak a vrátí jej jako celé číslo v rozsahu 0 – 255 (bajt), resp. 0 – 0xFFFF (char). ● Metoda čeká na to, dokud ● není k dispozici čtený bajt, resp. znak – pak jej vrátí, ● není dosaženo konce souboru (pak v obou případech vrátí -1 ) nebo ● není detekována nějaká chyba (pak vyvolá výjimku IOException )
Copyright © 2008, Rudolf Pecinovský 54 Metody vstupních proudů2/3 ►Stream: int read(byte[] b) Reader: int read(char[] cbuf) ● Přečte ze vstupu další bajty, resp. znaky do zadaného vektoru a vrátí počet přečtených bajtů, resp. znaků. ● Metoda čeká na to, dokud ● nejsou nějaké bajty (znaky) k dispozici nebo ● dokud není dosaženo konce souboru nebo ● dokud není detekována nějaká chyba (pak vyvolá IOException ). ● Pokud nic nepřečte, protože bylo dosaženo konce souboru vrátí -1. ►Stream: int read(byte[] b, int off, int len) Reader: int read(char[] cbuf, int off, int len) ● Obdobně jako předchozí, jenom čte do předem definované části zadaného pole ►void close() ● Uzavře proud a uvolní alokované zdroje. Uzavření dříve uzavřeného proudu neudělá nic.
Copyright © 2008, Rudolf Pecinovský 55 Metody vstupních proudů3/3 ► long skip(long n) ● Přeskočí na vstupu zadaný počet bajtů (znaků). Vrátí skutečný počet přeskočených bajtů (znaků). ► boolean markSupported() ● Vrátí informaci o tom, zda daný proud podporuje umísťování značek. ► void mark(int readlimit) ● Označí zadanou pozici v proudu, aby se k ní mohl později vrátit. Parametr readlimit označuje, kolik bajtů (znaků) chce program mít možnost přečíst, než se k této zarážce vrátí a začne od ní číst znovu. ► void reset() ● Vrátí se v proudu k nastavené značce, aby odtud při příštím volání read začal znovu číst. Některé proudy umožňují volat reset bez předchozího volání mark a začínají pak číst celý proud znovu od počátku.
Copyright © 2008, Rudolf Pecinovský 56 Metody výstupních proudů1/2 ► void write(int b) ● Zapíše zadaný bajt, resp. znak na výstup. Z celého čísla, které je předáváno jako parametr, se na vstup pošle pouze příslušný počet nižších bajtů (stream 1, writer 2). Ostatní bajty jsou ignorovány. ►Stream: void write(byte[] b) Writer: void write(char[] cbuf) ● Pošle na výstup obsah zadaného vektoru. ►Stream: void write(byte[] b, int off, int len) Writer: void write(char[] cbuf, int off, int len) ● Pošle na výstup obsah len bajtů, resp. znaků ze zadaného vektoru od pozice off. ►Writer: void write(String s) Writer: void write(String s, int off, int len) ● Pošle na výstup zadaný řetězec, resp. jeho zadanou část.
Copyright © 2008, Rudolf Pecinovský 57 Metody výstupních proudů2/2 ► flush() ● Spláchne zadaný proud, tj. zabezpečí, aby se zapsaná data fyzicky dostala k požadovanému cíli. ● Je-li proud napojen na další proud, zabezpečí, aby se i tento proud spláchnul. ● Po úspěšně provedené operaci flush máme jistotu, že data jsou tam, kde mají být (pro případ následného zhroucení aplikace). ► close() ● Zavře daný proud a uvolní všechny alokované zdroje.
Copyright © 2008, Rudolf Pecinovský 58 Společné zásady ►Při čtení z disku a zápisu na disk je vhodné použít proudy s vyrovnávací pamětí, které práci velmi výrazně zrychlí ►Proudy by neměly zůstávat dlouho zbytečně otevřené, protože blokují zdroje OS ►Řada operací s proudy vyhazuje kontrolované výjimky. Tyto výjimky by neměly zůstat neošetřené. Neočekáváme-li, že k nim někdy dojde, měli bychom je ošetřit převodem na nekontrolované. ►Při práci s konzolou nastávají občas problémy s jazykovým nastavením – je třeba s nimi počítat
Copyright © 2008, Rudolf Pecinovský 59 Příklad: Převod kódování public class Převod_2 { //== KONSTANTNÍ ATRIBUTY TŘÍDY ======================================= private static final Charset ASCII_SET = Charset.forName("ASCII"); private static final PrintStream out = System.out; private static final PrintStream err = System.err; //== PROMĚNNÉ ATRIBUTY TŘÍDY ========================================= /** Kódová stránka zdrojových souborů. */ public static Charset sourceCP; /** Kódová stránka cílových souborů. */ public static Charset destCP; /** Kódová stránka výpisů na standardní výstup. */ public static Charset consoleCP; /** Složka se zdrojovými soubory. */ public static File sourceDir; /** Složka s cílovými soubory. */ public static File destDir;
Copyright © 2008, Rudolf Pecinovský 60 Příklad: převeďSoubor(File, File) private boolean převeďSoubor( File input, File output ) { println( out, "Převádíme soubor: " + input + "\n na soubor: " + output); LineNumberReader lnrd = otevřiSoubor( input ); OutputStream os = null; try { os = new BufferedOutputStream( new FileOutputStream( output ) ); }catch( IOException e ) { problém(e, "Nepodařilo se otevřít výstupní soubor " + output); }//try writer boolean odháčkovat = destCP.equals(ASCII_SET); try { String řádek; while( (řádek = lnrd.readLine()) != null ) { os.write( řádek.getBytes( destCP ) ); os.write( '\n' ); } }catch( IOException e ) { problém( e, "Při převodu ze souboru " + input + " do souboru " + output + " došlo k chybě" ); }finally { zavřiSoubory(lnrd, input, os, output); } return true; }
Copyright © 2008, Rudolf Pecinovský 61 Příklad: zavřiSoubory /********************************************************************* * Zavře zadaný vstupní a výstupní proud a v případě problémů * vypíše příslušnou zprávu. * Souborové parametry slouží pouze k vypsání případné chybové zprávy. is Zavíraný vstupní proud input Soubor z nějž čte vstupní proud os Zavíraný výstupní proud output Soubor, kam zapisuje výstupní proud */ private void zavřiSoubory( Closeable is, File input, Closeable os, File output) { try { is.close(); } catch (IOException e) { problém(e, "Nepodařilo se zavřít vstupní soubor " + input); } try { os.close(); } catch (IOException e) { problém(e, "Nepodařilo se zavřít výstupní soubor " + output); }
Copyright © 2008, Rudolf Pecinovský 62 Příklad: otevřiSoubor (File) /********************************************************************* * Otevře zadaný soubor jako vstupní proud v potřebném kódování. * file soubor s parametry (měl by mít příponu.args). */ private LineNumberReader otevřiSoubor(File input) { LineNumberReader lnrd = null; try { FileInputStream fis = new FileInputStream( input ); Reader reader = new InputStreamReader( fis, sourceCP ); lnrd = new LineNumberReader( reader ); }catch( IOException e ) { problém( e, "Nepodařilo se otevřít vstupní soubor " + "\n" + input ); } return lnrd; }
Copyright © 2008, Rudolf Pecinovský 63 Příklad: kopírujSoubor(File, File) 1/2 private void kopírujSoubor( File input, File output ) { println( out, "Kopíruju soubor: " + input + "\n na soubor: " + output ); InputStream is = null; try { is = new BufferedInputStream( new FileInputStream( input ) ); }catch( IOException e ) { problém( e, "Nepodařilo se otevřít vstupní soubor " + "\n" + input ); }//try reader OutputStream os = null; try { os = new BufferedOutputStream( new FileOutputStream( output ) ); }catch( IOException e ) { problém( e, "Nepodařilo se otevřít výstupní soubor " + output ); }//try writer //... Pokračování na dalším snímku
Copyright © 2008, Rudolf Pecinovský 64 Příklad: kopírujSoubor(File, File) 2/2 try { int bajt; while( (bajt = is.read()) >= 0 ) { os.write( bajt ); } }catch( IOException e ) { problém( e, "Při kopírování ze souboru " + input + " do souboru " + output + " došlo k chybě" ); } finally { zavřiSoubory(is, input, os, output); }
Copyright © 2008, Rudolf Pecinovský 65 Příklad: převeďSložku(File, File) private boolean převeďSložku( File inputDir, File outputDir ) { if( !outputDir.exists() ) { outputDir.mkdirs(); } String[] seznam = inputDir.list(); //Převede jednotlivé soubory ve složce for( String název : seznam ) { File inFile = new File( inputDir, název ); File outFile = new File( outputDir, název ); if( inFile.isFile() ) { převeďSoubor( inFile, outFile ); } else if( inFile.isDirectory() ) { převeďSložku( inFile, outFile); } else { problém( new IllegalStateException(), " Převod selhal" ); } return true; }
Vaše jistota na trhu IT Copyright © 2008, Rudolf Pecinovský66 Definice dekorujících proudů
Základní pravidla ►Definujeme-li vlastní proud, většinou používáme Návrhový vzor adaptér Návrhový vzor adaptér ►Jako společný rodič běžných dekorátorů slouží FilterInputStream, FilterOutputStream, FilterReader a FilterWriter ►U vstupních proudů definují delegaci: ● Sady metod read(???) ● Metody close() ● Metody pro práci se značkami včetně informace o její podpoře ( markSupported(), mark(), reset() ) ►U výstupních proudů definují delegaci: ● Sady metod write(???) ● Metod close() a flush() ►Příklad: ASCIIReader x ASCIIWriter Copyright © 2008, Rudolf Pecinovský 67
Vaše jistota na trhu IT Copyright © 2008, Rudolf Pecinovský68 Serializace
Základy1/2 ►K serializaci a deserializaci objektů slouží proudy implementující rozhraní ObjectOutput a ObjectInput ►Obě rozhraní jsou potomky proudů DataOutput a DataInput vyžadujících schopnost ukládat a číst hodnoty primitivních datových typů a textových řetězců ►Knihovní verze těchto proudů představují instance tříd ObjectOutputStream a ObjectInputStream jsou ochotny pracovat pouze s objekty tříd implementujících rozhraní ►Rozhraní Serializable je značkovací rozhraní, jehož implementací třída pouze slibuje, že její objekty jsou schopny korektní serializace Copyright © 2008, Rudolf Pecinovský 69
Základy2/2 ►O základní funkčnost procesu se však stará systém, přesněji vstupní, resp. výstupní proud, do kterého objekty dané třídy serializujeme, resp. ze kterého je deserializujeme ►Serializovatelná je značná část tříd standardní knihovny, mezi jiným: ● Obalové typy, ● Textové řetězce, ● Kontejnery ● Komponenty GUI Copyright © 2008, Rudolf Pecinovský 70
Vaše jistota na trhu IT Copyright © 2008, Rudolf Pecinovský71 Děkuji za pozornost Rudolf Pecinovský mail: ICQ:
Copyright © 2008, Rudolf Pecinovský 72
Copyright © 2008, Rudolf Pecinovský 73 Pgm Používaná písma a objekty ► Pgm Příliš žluťoučký kůň úpěl ďábelské ódy (Demi) ● Pgm Příliš žluťoučký kůň úpěl ďábelské ódy (Medium) ● Pgm Příliš žluťoučký kůň úpěl ďábelské ódy (Cond) ►Příliš žluťoučký kůň úpěl ďábelské ódy (Heavy) ● Příliš žluťoučký kůň úpěl ďábelské ódy (Franklin Gothic Book) ● Příliš žluťoučký kůň úpěl ďábelské ódy (Comic Sans MS) ● Příliš žluťoučký kůň úpěl ďábelské ódy (Consolas) Program Keyword Opakování Příliš žluťoučký kůň úpěl ďábelské ódy
Copyright © 2008, Rudolf Pecinovský 74 Konvence syntaktických definic Syntaktická definice = pravidla zápisu konstrukce jazyka Název–Název definované součásti součást –Název součásti definované jinde program –Text, který se přímo použije (opíše) [ ]–Obsah hranatých závorek je volitelný { | }–Výběr z několika možností oddělených | –Druhou možností je psaní možností pod sebe …–Předchozí položka se může opakovat ¶–Definice pokračuje na dalším řádku kde bude navíc odsazená Příklad:Identifikátor:písmeno [ { písmeno | číslice } ] … Číslice: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 Originál: P02_Prvni_kod.ppt#23. Konvence syntaktických definicP02_Prvni_kod.ppt#23. Konvence syntaktických definic