Datový proud: Porovnání verzí

Smazaný obsah Přidaný obsah
Malá editace
m wikify, linky -> reference, ...
Řádek 1:
'''Datové proudy''' (dále jen proudy) jsou [[sekvence]] '''[[data|dat]]'''. Proud je definován svým [[vstup|vstupem]] a [[výstup|výstupem]], těmi mohou být například '''[[soubor]]''' na disku, '''[[zařízení]]''' (vstupní [[klávesnice]] nebo [[myš]], výstupní [[displej]]) nebo jiný '''[[program]]'''. [[Primitivní proudy]] pouze přenášejí '''[[binární]]''' data, specializované proudy umí s přenášenými daty manipulovat. Tyto manipulační schopnosti se liší podle typu přenášených dat.
{{wikifikovat}}
 
'''Datové proudy''' (dále jen proudy) jsou [[sekvence]] '''[[data|dat]]'''. Proud je definován svým vstupem a výstupem, těmi mohou být například '''[[soubor]]''' na disku, '''[[zařízení]]''' (vstupní klávesnice nebo myš, výstupní [[displej]]) nebo jiný '''[[program]]'''. [[Primitivní proudy]] pouze přenášejí '''[[binární]]''' data, specializované proudy umí s přenášenými daty manipulovat. Tyto manipulační schopnosti se liší podle typu přenášených dat.
 
Datové proudy mohou být potenciálně nekonečné (tzv. [[codata]]), čímž se liší od běžných konečných dat.
Řádek 7 ⟶ 5:
== Přehled ==
 
Proudy vznikly jako náhrada [[Rigidita|rigidního]] propojení [[proces]]ů a zařízení v [[Unix|Unixu]] v 80. letech 20. století. Před zavedením proudů se programy musely explicitně připojovat k zařízením a programům. Programátor musel brát v úvahu různá '''[[rozhraní''']], různou reprezentaci dat. Datové proudy umožnily od těchto problémů [[abstrakce|abstrahovat]] vytvořením jednotného rozhraní.
 
Dennis Ritchie popisuje proudy jako plně '''duplexní''' (obousměrné) spojení mezi uživatelským procesem a zařízením popř. pseudozařízením. Skládá se z několika lineárně spojených zpracovávajících '''modulů'''; je analogický k Shell pipeline, přičemž data mohou proudit oběma směry. Moduly v proudu mezi sebou komunikují prostřednictvím '''zpráv'''.
[[Dennis Ritchie]] popisuje proudy jako plně duplexní (obousměrné) spojení mezi uživatelským procesem a zařízením popř. pseudozařízením. Skládá se z několika lineárně spojených zpracovávajících modulů; je analogický k [[Shell pipeline]], přičemž data mohou proudit oběma směry. Moduly v proudu mezi sebou komunikují prostřednictvím zpráv. Na konci proudu, který je blíže procesu, je sada [[funkce|funkcí]], které zprostředkovávají rozhraní se zbytkem systému. Požadavky uživatele na zápis a ovládání [[I/O]] jsou transformovány ve zprávy a odeslány proudu, požadavky na čtení přebírají data z proudu a předávají je uživateli. Na opačném konci proudu se nachází [[ovladač]] zařízení. Data přicházející z proudu jsou předávána zařízení a znaky a stavy zaznamenané zařízením jsou zabaleny do zpráv a odeslány přes proud směrem k uživatelskému programu. Další moduly, které zapojeny do proudu, mohou s procházejícími daty manipulovat.
 
Každý modul zapojený v proudu je složen ze dvou [[fronta (datová struktura)|front]], každou pro jeden směr. Kromě dat jsou s frontami spojeny i procedury ''put'' (vlož), která vkládá data do [[fronta|fronty]], a ''service'' (obsluž), která je volána kdykoli jsou k dispozici data ke zpracování.
Proudy byly implementovány v UNIXu v roce 1984. Zároveň byly v jazyce [[C (programovací jazyk)|C]] implementovány potřebné funkce a typy, které umožnily s datovými proudy pracovat.[http://cseweb.ucsd.edu/classes/fa01/cse221/papers/ritchie-stream-io-belllabs84.pdf]
 
Proudy byly implementovány v UNIXu v roce 1984. Zároveň byly v jazyce [[C (programovací jazyk)|C]] implementovány potřebné funkce a typy, které umožnily s datovými proudy pracovat.[<ref>{{Citace elektronické monografie|příjmení = Ritche|jméno = Dennis|titul = A Stream Input-Output System|url = http://cseweb.ucsd.edu/classes/fa01/cse221/papers/ritchie-stream-io-belllabs84.pdf]|vydavatel = AT&T|místo = |datum vydání = October, 1984|odkaz na autora = Dennis Ritchie}}</ref>
 
== Standardní proudy ==
{{Podrobně|Standardní proudy}}
Systém vytváří ke spouštěným procesům tři '''popisovače''', ke kterým se programy připojují prostřednictvím proudů. Jeden standardní vstup (0), jeden standardní výstup (1) a jeden chybový výstup (2). Pokud je proces spuštěn v [[Terminál (informatika)|terminálu]], [[Standardní vstup|standardním vstupem]] je text napsaný do okna terminálu. U textových zpráv z programu je terminálové okno naopak příjemcem. Tyto proudy je možno přesměrovat. Procesu je možno operátorem ‚<‘ nastavit standardní vstup tak, aby četl například ze souboru.
Pokud je proces spuštěn v '''terminálu''', standardním vstupem je text napsaný do okna terminálu. U textových zpráv z programu je terminálové okno naopak příjemcem. Tyto proudy je možno přesměrovat. Procesu je možno operátorem ‚<‘ nastavit standardní vstup tak, aby četl například ze souboru.
<pre>more < vstup.txt</pre>
Analogicky lze výstup programu přesměrovat operátorem ‚>‘. Pro přesměrování standardního chybového výstupu je třeba uvést před operátorem číslo popisovače, tedy 2.
Řádek 23 ⟶ 22:
== Proudy v Javě ==
 
V jazyku [[Java (programovací jazyk)|Java]] existuje několik [[Třída (programování)|tříd]], které se zabývají přenosem různých typů dat. Většina z nich se nachází v balíčku (''package'') <tt>''java.io''</tt>. Třídy pro práci se soubory se nacházejí v balíčku <tt>''java.nio.file''</tt>.[<ref>{{Citace elektronické monografie|příjmení = |jméno = |titul = Lesson: Basic I/O|url = http://docs.oracle.com/javase/tutorial/essential/io/index.html]|vydavatel = Oracle|místo = |datum vydání = 2015|korporace = Oracle}}</ref>
 
=== Bajtové proudy ===
 
Všechny vstupní třídy jsou potomky třídy <tt>''InputStream''</tt> a výstupní třídy potomky <tt>''OutputStream''</tt>. Nejzákladnějším typem proudu je [[bajt|bajtový]] proud. Tento proud čte nebo zapisuje data na nízké úrovni po 8 bitových svazcích. Doporučuje se tento typ proudu nepoužívat, protože existují specializovanější alternativy (viz dále).
 
==== Příklad ====
Řádek 35 ⟶ 34:
import java.io.IOException;
 
[[public]] [[Třída (programování)|class]] ZkopírujBajty {
public static [[void]] main(String[] args) throws [[Výjimka (programování)|IOException]] {
 
FileInputStream in = null;
Řádek 62 ⟶ 61:
==== Uzavírání proudů ====
 
V tomto případě je čten obsah souboru <tt>''vstup.txt''</tt> bajt po bajtu a ukládán do souboru <tt>vystup.txt</tt>. Oba proudy je třeba po použití uzavřít, protože těchto proudů může [[operační systém]] poskytnout omezené množství.
 
=== Znakové proudy ===
 
Java používá pro vnitřní reprezentaci znaků kódování '''[[Unicode''']]. Znakové proudy s tím počítají a dokážou toto kódování při zápisu a čtení překládat na jiná. Všechny vstupní třídy jsou potomky třídy <tt>''Reader''</tt> a všechny výstupní třídy jsou potomky třídy <tt>''Writer''</tt>.
 
==== Příklad ====
Řádek 101 ⟶ 100:
=== Proudy s vyrovnávací pamětí ===
 
Běžně je každý požadavek na zápis nebo čtení zpracováván přímo operačním systémem. To může vést k neefektivitě programu, protože každý takový požadavek může potřebovat např. přistupovat k [[disk|disku]] nebo [[Síťová vrstva|síťovým zdrojům]], což jsou časově relativně náročné operace. '''[[Vyrovnávací paměť''']] (''buffer'') je místo v [[Operační paměť|operační paměti]] vyhrazené pro dočasné uchování dat před jejich přesunem na jiné místo. Pouze pokud je vyrovnávací paměť prázdná, použije se běžný přístup. Proudy lze „naučit“ používat vyrovnávací paměť využitím návrhového vzoru '''[[dekorátor''']]. Proud, který čte ze souboru a využívá vyrovnávací paměť je možno vytvořit následovně:
Proud, který čte ze souboru a využívá vyrovnávací paměť je možno vytvořit následovně:
<pre>inputStream = new BufferedReader(new FileReader("vstup.txt"));</pre>
Nejprve se vytvoří proud pro čtení ze souboru (<tt>''FileReader''</tt>) a ten poté „obalí“ proud pracující s vyrovnávací pamětí (<tt>''BufferedReader''</tt>). Obdobně pracuje i výstupní proud:
<pre>outputStream = new BufferedWriter(new FileWriter("characteroutput.txt"));</pre>
V Javě existují celkem 4 třídy, které obalují proudy: <tt>''BufferedInputStream''</tt>, <tt>''BufferedOutputStream''</tt>, <tt>''BufferedReader''</tt>, <tt>''BufferedWriter''</tt>.[<ref>{{Citace elektronické monografie|příjmení = |jméno = |titul = Buffered Streams|url = http://docs.oracle.com/javase/tutorial/essential/io/buffers.html]|vydavatel = Oracle|místo = |datum vydání = 2015|korporace = Oracle|odkaz na korporaci = Oracle}}</ref>
 
==== Vyprázdnění vyrovnávací paměti ====
 
Je dobrým zvykem vyprazdňovat vyrovnávací paměť (zapsat změněná data) na kritických místech. Tato operace uloží celý obsah vyrovnávací paměti na cíl proudu (soubor, zařízení atd.) Běžně se používá anglický výraz „flush“„''flush''“.
 
==== Dekorátor ====
{{Podrobně|Dekorátor}}
Dekorátor je '''[[návrhový vzor''']], který se používá k obohacení existujících objektů o přidanou funkcionalitu. Funkce, které neupravuje, deleguje na obalený objekt. V angličtině se člověk může setkat s označením „wrapper“„''wrapper''“.
Uplatnění tento vzor najde třeba při tvorbě [[GUI]], kdy lze například podkladovou třídu
<pre>Okno o = new Okno();</pre>
obohatit o titulek tak, že
<pre>o = new OknoSTitulkem(o);</pre>
a dále třeba o [[posuvník]]
<pre>o = new OknoSPosuvníkem(o);</pre>
 
=== Datové proudy ===
 
Java obsahuje třídy pro pohodlné čtení a zápis primitivních [[datový typ|datových typů]] a typu <tt>''String''</tt>. Nejrozšířenější třídy jsou <tt>''DataInputStream''</tt> a <tt>''DataOutputStream''</tt>. <tt>''String''</tt> je ukládán v kódování [[UTF-8]]. Údaje takto uložené např. do souboru nejsou uživatelsky přívětivé a s výjimkou řetězců čitelné. Metody pro čtení jsou <tt>readDouble''read[[Desetinná čárka|Double]]''</tt>, <tt>readInt''read[[číslo|Int]]''</tt>, <tt>''readUTF''</tt>. Obdobně metody pro zápis mají předponu <tt>''write''</tt>.
 
=== Objektové proudy ===
 
Většina standardních tříd implementuje rozhraní <tt>''Serializable''</tt> (serializovatelný), které je nezbytné pro jejich podporu [[Objekt (programování)|objektovými]] proudy. Objektové proudy rozšiřují datové proudy, ''takže objektové proudy umí pracovat i s primitivními datovými typy''. Nové metody jsou <tt>''readObject''</tt> a <tt>''writeObject''</tt>. Pokud metoda <tt>''readObject''</tt> vrátí jiný než očekávaný objekt, vyhodí výjimku typu <tt>''ClassNotFoundException''</tt>.
 
Pokud se objekt neskládá jen z primitivních typů ale i z '''[[Reference (programování)|referencí''']] na další objekty, je potřeba zachovat tyto reference. Proto je při zápisu objektu uložit i všechny objekty, na které má daný objekt odkaz. Podobně se bude chovat čtecí proud, který se bude snažit zrekonstruovat celou takovou síť objektů.[<ref>{{Citace elektronické monografie|příjmení = |jméno = |titul = Object Streams|url = http://docs.oracle.com/javase/tutorial/essential/io/objectstreams.html]|vydavatel = Oracle|místo = |datum vydání = 2015|korporace = Oracle}}</ref>
 
== Odkazy ==
 
=== Zdroje ===
*[[Rudolf Pecinovský|Pecinovský, Rudolf]]. ''Návrhové vzory''. [[Brno]] : [[Computer Press|COMPUTER PRESS]], 2007. 978-80-251-1582-4.
 
=== Reference ===
<references />[[Kategorie:Datové struktury]]