"Hej, Amigo! Idag ska vi bekanta oss med input/output-strömmar . Vi valde detta ämne för ett par dagar sedan, men idag ska vi utforska det grundligt. Input/output-strömmar är indelade i fyra kategorier:"

1) Strömmar är uppdelade efter deras riktning: ingångsströmmar och utgående strömmar

2) Strömmar är uppdelade efter deras datatyp: de som arbetar med bytes och de som arbetar med tecken .

Här är dessa divisioner representerade i en tabell:

Ingångsström Utgångsström
Fungerar med bytes InputStream OutputStream
Arbetar med karaktärer Läsare Författare

Om ett objekt implementerar InputStream- gränssnittet, stöder det möjligheten att sekventiellt läsa bytes från det.

Om ett objekt implementerar OutputStream- gränssnittet stöder det möjligheten att sekventiellt skriva byte till det.

Om ett objekt implementerar Reader- gränssnittet, stöder det möjligheten att sekventiellt läsa tecken (tecken) från det.

Om ett objekt implementerar Writer- gränssnittet, stöder det möjligheten att sekventiellt skriva tecken (tecken) till det.

In-/utgångsströmmar - 1

En utdataström är som en skrivare. Vi kan mata ut dokument till skrivaren. Vi kan mata ut data till en utgångsström.

En ingångsström kan å sin sida jämföras med en scanner, eller kanske ett eluttag. Med en skanner kan vi föra in dokument till vår dator. Eller så kan vi koppla in i ett eluttag och ta emot el från det. Vi kan ta emot data från en ingångsström.

"Var används de?"

"Dessa klasser används överallt i Java. Vår välbekanta vän System.in är en statisk InputStream -variabel namngiven i klassen System ."

"Seriöst?! Så hela den här tiden har jag använt en InputStream och inte ens insett det. Är System.out också en stream?"

"Ja, System.out är en statisk PrintStream (en avkomling av OutputStream ) variabel i klassen System."

"Du menar att berätta för mig att jag alltid har använt streams och inte ens visste om det?"

"Ja, och det säger oss bara hur bekväma dessa strömmar är. Du bara tar en och använder den."

"Men du kan inte säga det om System.in. Vi var hela tiden tvungna att lägga till BufferedReader eller InputStreamReader till den."

"Det är sant. Men det fanns också skäl till det."

Det finns många datatyper och många sätt att arbeta med dem. Så antalet standard I/O-klasser växte väldigt snabbt, även om de gjorde allting på nästan samma sätt. För att undvika denna komplexitet använde Java-utvecklare abstraktionsprincipen och delade upp klasser i många små delar.

Men du kan koppla ihop dessa delar på ett sammanhängande sätt och få mycket komplex funktionalitet, om du behöver det. Titta på det här exemplet:

Mata ut en sträng till konsolen
System.out.println("Hello");
Lagra konsolutgångsströmmen i en separat variabel.
Mata ut en sträng till strömmen.
PrintStream console = System.out;
console.println("Hello");
Skapa en dynamisk (expanderande) byte-array i minnet.
Anslut den till en ny utgångsström (PrintStream-objekt).
Mata ut en sträng till strömmen.
ByteArrayOutputStream stream = new ByteArrayOutputStream();
PrintStream console = new PrintStream(stream);
console.println("Hello");

"Ärligt talat, det här är som ett Lego-set. Bara det är inte klart för mig vad någon av den här koden gör."

"Oroa dig inte för det nu. Allt i sin egen tid."

Det här är vad jag vill att du ska komma ihåg: Om en klass implementerar OutputStream-gränssnittet kan du skriva bytes till den. Nästan exakt som du matar ut data till konsolen. Vad den gör med den är dess sak. Med vårt "Lego-kit" bryr vi oss inte om syftet med varje enskild del. Vi bryr oss om att det stora urvalet av delar låter oss bygga så coola saker.

"Okej. Var ska vi börja då?"