|
||||||||||||||||||||||||||||||||||||||||||||||||
Menu
Distributions (131)
Software (10844)
|
Java (15) - I/O operace I.Jednou z klíčových činností v programech je výměna dat s okolním
světem. V Javě to jde velice snadno a elegantně.
Základní informace o streamechVstupně/výstupní operace lze v Javě realizovat několika způsoby. My se nyní zaměříme na ten základní způsob, tedy práci se streamy. Téměř každý, kdo programuje v nějakém jazyce, bude pojem stream znát. A právě v Javě se tomuto slovu dostává plného významu. Stream si lze představit jako trubku, jejíž konec máme k dispozici a můžeme "čerpat" data z něho (tedy číst) nebo naopak do něho (tj. zapisovat). Streamů existuje (z hlediska implementace) celá řada, z pohledu uživatele se však všechny streamy daného směru (tedy "dovnitř" nebo "ven") chovají skoro stejně - většinu funkcionality mají společnou. Pro streamy je charakteristická především jejich sekvenčnost. I když to neplatí úplně stoprocentně (existují streamy se "zpětným chodem"), s daty se pracuje v konkrétním neměnném pořadí. Streamy v Javě
V Javě je každý stream reprezentován jako objekt, tedy instance nějaké třídy.
Balík
Známe dvě hlavní kategorie streamů: binární a textové. Liší se způsobem práce
se znaky, binární streamy pracují se "surovými" bajty (tak, jak jsou), zatímco
streamy textové pojímají bajty, resp. skupiny bajtů způsobem, který odpovídá
nastavení prostředí.
Binární vstupní streamy jsou odvozeny od abstraktní třídy Základy práce se streamyKaždý stream má svůj životní cyklus - je velmi jednoduchý a sestává z těchto etap:
Ošetření chyb
Důležitým aspektem práce se streamy je ošetření chyb, které se mohou
vyskytnout. Téměř všechny chybové stavy jsou řešeny výjimkami. Tou základní
je
Jak jsem již uvedl, výjimku Základní druhy streamůSe streamy pracujeme prakticky stejně, ať už se jedná o data v souborech na disku, o síťovou komunikaci, komunikaci mezi vlákny apod. I když je tato práce téměř shodná, existují podstatné rozdíly zejména v přípravě streamů před komunikací. Podíváme se tedy blíže na jednotlivé druhy streamů. Souborové streamyAsi nejčastějším způsobem komunikace s vnějším prostředím je čtení a zápis souborů. Z hlediska Javy se nerozlišují vlastnosti souborového systému, se soubory se pracuje vždy stejně, jen nás zajímá, zda soubor existuje, lze z něj číst nebo do něj zapisovat. try { InputStream is = new FileInputStream("soubor.dat"); // stream se hned otevře int i = 0; while ((i = is.read()) >= 0) { // čte se, dokud není konec souboru ... } is.close(); // zavření souboru } catch (IOException e) { ... // zpracování výjimky }
Příklad ukazuje základní způsob čtení ze streamu, v tomto případě souborového.
Stream se otevře, v cyklu se z něho čte po bajtech (pozor - i když se čtou
bajty, hodnota je typu Řetězcové streamy
Podobně jako třeba v C++, i v Javě lze snadno číst z řetězce a zapisovat do
něj streamovým způsobem. Stream pracuje nad objektem typu
Následující příklad ukazuje, jak se streamově zapisuje do řetězce. Stream je
samozřejmě textově orientovaný, což je naprosto v souladu s daným účelem.
Pro výstupní řetězcové streamy je charakteristické, že operace nevyhazují výjimku
StringWriter sw = new StringWriter(); sw.write("abcd"); sw.write(sw.toString()); // obsahu streamu se zapíše zpět do streamu System.out.println(sw);
Copak asi uvedený příklad dělá? Zapíše uvedený řetězec dvakrát za sebou
(nejprve přímo, potom prostřednictvím metody Mezi základní streamy patří ještě některé další druhy, ale o těch si řekneme až později. Nejdřív by se totiž hodilo znát něco jiného... Filtrové streamyNejvětší množství streamů patří do obrovské množiny, které se říká filtrové streamy. Takový stream si lze představit skutečně jako nějaký kus trubky s filtrem. Nejobecněji to vypadá tak, že tento stream napasujeme na nějaký jiný stream. Data, která přes filtrový stream procházejí, mohou být různě pozměněna, stream je může všelijak zkoumat a něco počítat atd. Filtrové streamy lze prakticky libovolně řetězit za sebe (pokud na sebe navazují stejné kategorie, ve smyslu binární a textové). Filtrových streamů je celá řada, řekneme si tedy nejprve o těch nejdůležitějších. Bufferované streamyProtože často pracujeme s malými objemy dat, nebývají vstupně/výstupní operace příliš operačně výkonné. Záleží na prostředcích operačního systému, druhu streamu atd., a většinou nemůžeme na nic spoléhat (píšeme platformově nezávislé programy!). Proto existují streamy, které obsahují vlastní buffer a optimalizují přístupy k datům. Představme si, že zapisujeme data třeba po jednom bajtu - to by za normálních okolností mohlo znamenat třeba mnoho zbytečných přístupů na disk, posílání "prázdných" paketů po síti apod. Přitom obvykle není žádný důvod, aby se data okamžitě sunula někam dál. Pro optimalizaci tedy použijeme bufferovaný stream. try { BufferedReader br = new BufferedReader(new FileReader("soubor.txt")); String s = ""; while ((s = br.readLine()) != null) { ... } br.close(); } catch (IOException e) { ... } Příklad ukazuje hned několik aspektů práce s bufferovaným (textovým) streamem. Filtrové streamy obvykle vytváříme tak, že předáme jejich konstruktoru jako parametr podřízený stream, v daném případě textový souborový. Dále je vidět, že zde můžeme číst celé řádky - to je věc specifická právě pro tento stream, ale i zde můžeme stále číst jednotlivé znaky, toto je jen usnadnění. Po skončení práce uzavřeme "nejvrchnější" stream, ten už zajistí kaskádovitě uzavření všech ostatních.
Ještě důležitá poznámka - při použití bufferovaných výstupních streamů není
zaručeno, kdy se data z bufferu přesunou do navazujícího streamu. K zajištění
zápisu dat z bufferu proto v případě potřeby voláme metodu Konverzní streamyNázev není úplně přesný, řeč bude pouze o konverzi mezi textovými a binárními streamy. V řadě případů totiž odněkud získáme binární stream, a přitom potřebujeme textový. Vřadíme tedy mezičlánek, který nám konverzi zajistí. Viz příklad: try { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int i = 0; while (i >= 0) { i = br.read(); if (i >= 0) { char c = (char) i; ... } } br.close(); } catch (IOException e) { ... } V příkladu je použit standardní vstup (čili obvykle klávesnice), který však je binární. Protože potřebujeme znaky, musíme provést převod, a to nejlépe hned "na cestě", pomocí konverzního streamu. Streamy pro kompresi/dekompresi datJako takovou třešničku na dortu, která ukáže, co se také se streamy dá dělat, si nyní vyzkoušíme dekompresi dat a zároveň výpočet kontrolního součtu. Na samém konci budeme číst po řádcích textová data. Stačí jen streamy zřetězit za sebe... try { CheckedInputStream cis = new CheckedInputStream(new GZipInputStream(new FileInputStream("data.gz"))); BufferedReader br = new BufferedReader(new InputStreamReader(cis)); String s = ""; while ((s = br.readLine()) != null) { ... } System.out.println("Kontrolni soucet je: " + cis.getValue()); br.close(); } catch (IOException e) { ... } Jak snadné... A tohle zdaleka není všechno, co streamy dovedou. Příště se podíváme na některé další druhy streamů (těch zajímavých je ještě řada), řekneme si něco o tom, jak efektivně a bezpečně přenášet různá data, a také jak si vyrobit vlastní stream pro specifické účely.
|
Search Software
Search Google
|
||||||||||||||||||||||||||||||||||||||||||||||
©Pavel Kysilka - 2003-2024 | maillinuxsoft.cz | Design: www.megadesign.cz |