Takže si to vezměme hezky popořádku. Stream je v Javě implementován dost blbě a nikdo se nad tím očividně řádně nezamyslel. Ve světě OOP mi opravdu označení pro Stream - tedy obecně proud něčeho - nepříjde vůbec nějak volné, ale naprosto jednoznačně se odkazující ke specifikaci, nad jakým typem dat to má vlastně proud má být. Viz Java 8 - Streamy.
Vezměte to popořádku. Nejprve získejte nějaké znalosti, a pak o tom něco pište. InputStream a OutpuStream jsou v Javě od verze 1.0, tedy od roku 1996. Stream API bylo přidáno do Javy ve verzi 8, tedy v roce 2014. Spletl jste se jenom o 18 let.
Takže takový příklad, který vám poslouží jako taková berlička, pane Jirsáku, abyste konečně vymanil z te nevědomosti a pochopil, že bufferování nehraje roli při rozhodování, zda-li něco je stream nebo není:
Kde jsem psal, že bufferování hraje roli při rozhodování, že je něco stream? Aha, nikde, to vy jenom neumíte číst. Zkusím vám to vysvětlit ještě jednou. Některé formáty dat jsou uspořádané tak, že k interpretaci dat, které jsou v proudu dat dříve, potřebujete informaci, která je v proudu dat až později. Pokud máte náhodný přístup ke všem datům, není to žádný problém – prostě si nejprve přečtete ten konec, zjistíte potřebné informace a na jejich základě pak přečtete začátek. Pokud ale ta data dostáváte od začátku do konce, tenhle postup použít nemůžete – když dostanete ta data na začátku, ještě nevíte, co s nimi máte dělat, musíte si je odložit někam stranou (do nějakého bufferu) a později se k nim vrátit.
Zkusím vám to uvést na takovém příkladu, jde jen o sčítání a odčítání malých čísel, to už jste snad ve škole bral. My jsme zvyklí používat infixovou notaci, kdy jsou tyto matematické operátory uvedené mezi operandy, třeba
5 + 3 - 7. Zkuste si, jak byste naprogramoval výpočet, kdybyste měl na vstupu stream operandů a operátorů zapsaných v tomhle pořadí (tedy byste měl stream
5, +, 3, -, 7). Dá se to udělat tak, že nemusíte nic bufferovat, pouze si budete pamatovat aktuální mezivýsledek a prováděnou operaci (což by se také dalo chápat jako buffer, ale nebudu vám to komplikovat).
Pro zápis matematických operací se dá ale použít také třeba postfixová notace, nebo-li reverzní polská notace (RPN). V té se zapisují nejprve operandy a teprve za nimi je operátor. Ten výše uvedený příklad můžete v RPN zapsal jako
5 3 7 - +6. (Ty dva zápisy nejsou ekvivalentní, tohle odpovídá v infixové notaci zápisu
5 + (3 - 7). Ale pro ulehčení jsem zvolil jen sčítání a odčítání, které mají stejnou prioritu, tudíž ani v infixové notaci nejsou závorky potřeba.) Opět máte na vstupu stream operandů a operátorů, tentokrát tedy
5, 3, 7, -, +. Dokážete naprogramovat výpočet jenom na základě toho streamu, aniž byste si musel bufferovat přicházející hodnoty, tj. ukládat si je do nějakého zásobníku?
Vám totiž nejde do hlavinky, že i input stream, který musí načíst nejprve celý vstupní stream, je rovněž stream.
Napsal jsem někde něco, z čeho by toto plynulo? Aha, nenapsal, to jenom vy neumíte číst. Napsal jsem, že aby bylo možné s tím zip archivem pracovat správně, musíte stejně celý ten stream přečíst a nabufferovat si ho, tj. zapsat někam, kde k němu budete mít přístup pro náhodné čtení – třeba do RAM nebo na disk.
A v tom je ten problém, který vy stále nechápete. Protože to bufferování může být operace velmi náročná na zdroje. Ano, nějaká knihovna to před vámi může skrýt, aby to mohli používat i takoví neumětelové, jako vy. Jenže to vám bude fungovat jen v jednoduchých případech. Když vám pak někdo pošle 100 GB zip („prosím vypal mi tenhle Blue-ray“) a ta vaše knihovna se ho pokusí celý načíst do paměti, nedopadne to moc slavně.
Takže ne, není pravda, co tvrdíte, že každá implementace ZipStreamu musí nutně na výstup posílat rovněž nevalidní soubory.
Což jsem opět nikde netvrdil, to jenom vy neumíte číst. Já jsem napsal, že pokud nemám přístup k datům zipu pro náhodné čtení (tj. mohu si kdykoli zvolit, kterou část zipu přečtu), ale mám k dispozici jenom proud bajtů, musím si ten proud bajtů odkládat někam, kde budu mít ten náhodný přístup – protože jedině tak dokážu zajistit, že ten příchozí zip archiv zpracuju správně.
Takto se to rozhodli udělat v Javě a je to samozřejmě špatně, protože to neuvedli v dokumentaci.
Jak už jsem psal, ta třída je velmi stará a dokumentace ještě pochází z doby, kdy programátoři rozuměli tomu, co dělají. Programátor, který zná formát zip archivu a přečte si tu dokumentaci, pochopí, jaká to má úskalí. Dneska už programují lidé jako vy, takže by v té dokumentaci mělo být uvedeno, ať se té třídě obloukem vyhnou lidé, kteří o formátu zip nic nevědí.
Dále, je-li v nějaké knihovně třída pro práci se zip archivy, pojmenujme ji teď lépe ZipArchive, očekává se od ní, že uživatelům umožní rozbalit soubor, který chtějí. Když nějaký uživatel bude používat tuto třídu ZipArchive, očekává, že bude správně fungovat, ne, že fungovat nebude.
Což je přesně to, co dělá třída
java.util.zip.ZipFile. Nebo vy snad máte nějaký příklad, kdy funguje špatně?
Je takový problém, aby se v případě, že dochází paměť, začalo prostě bufferovat na disk?
Ano, je to problém třeba v případě, kdy nemáte k dispozici disk, na který můžete zapisovat. Nebo v případě, kdy na disku nemáte volné místo.
Nic jiného k zajištění správné funkce ani není možné
Ale je to možné. Víte, občas někdo přijde s takovou školní úlohou, že má vypsat názvy souborů v tom zipu. Proč by pak rozbaloval ty soubory na disk, když je vůbec nepotřebuje? Když vám pošlu po síti 100 GB zip s úkolem, že máte vypsat názvy souborů v něm obsažených, a vy máte aplikaci spuštěnou na bezdiskovém počítači se 4 GB RAM, je to bez problémů splnitelný úkol. Akorát to musí naprogramovat někdo, kdo aspoň trochu ví, o co jde.
takže proč vy vlastně tvrdíte, že je to problematické a že si to musí každý naimplementovat sám podle svých potřeb?
Protože o té problematice alespoň něco malilinko vím. Vám, který o tom nevíte vůbec nic, se to samozřejmě všechno zdá snadné. Jenom se to naučit a mohl byste to naimplementovat.
Pane Jirsáku, vemte si někdy taky dovolenou, oddechněte si, sportujte, nechoďte tolik na sluníčko a bude to zase fajn.
Mám pro vás špatnou zprávu. Pokud byste se někdy skutečně naučil alespoň základy programování, pochopíte, jak hloupé byly vaše komentáře v této diskusi. Teď to vědět nemůžete, protože když nevíte vůbec nic, nemáte ani znalosti na to, abyste pochopil, jak málo toho víte.
Já jsem tady mluvil o Streamech abstraktních, řekl jsem, že Java 8 Stream api tuto abstraktnost cti ale InputStream a Jirsák ji nectí. To je jedna věc.
Už jsem vám vysvětloval, že IO streamy v Javě tento název ctít nemohou, když vznikly asi tak 15 let před tímto názvem.
Druhá věc je, že nechci proudově zpracovávat formát, který proudem není, jen tvrdím, že je možné ho proudově zpracovat, ikdyž to znamená, že se musí nejprve celý načíst. To, že se musí celý načíst, neznamená, že to nemůže být proud.
Akorát když ten proud načtete do paměti s náhodným přístupem a pracujete pak s tou pamětí, nepracujete už s proudem dat, ale s pamětí s náhodným přístupem. Ten postup „načíst do paměti“ není možné provést vždy – proud je potenciálně nekonečný, a to se vám do paměti fakt nevejde.
Ale je to marné, je to marné, je to marné.
Není to marné. Naučili se to jiní před vámi, není důvod, proč byste se nenaučil programovat i vy. Není to těžké.