1. Datastrømme
Sjældent eksisterer et program som en ø for sig selv. Programmer interagerer normalt på en eller anden måde med "omverdenen". Dette kan ske ved at læse data fra tastaturet, sende beskeder, downloade sider fra internettet eller omvendt uploade filer til en ekstern server.
Vi kan referere til alle disse adfærd i ét ord: dataudveksling mellem programmet og omverdenen. Vent, det er ikke kun et ord.
Selve dataudvekslingen kan selvfølgelig opdeles i to dele: modtagelse af data og afsendelse af data. For eksempel læser du data fra tastaturet ved hjælp af et Scanner
objekt - det er at modtage data. Og du viser data på skærmen ved hjælp af en System.out.println()
kommando - dette er at sende data.
I programmering bruges udtrykket "stream" til at beskrive dataudveksling. Hvor kom det udtryk fra?
I det virkelige liv kan du have en strøm af vand eller en strøm af bevidsthed. I programmering har vi datastrømme .
Streams er et alsidigt værktøj. De giver programmet mulighed for at modtage data fra hvor som helst (inputstrømme) og sende data overalt (outputstrømme). Der er således to typer:
- En inputstrøm er til at modtage data
- En outputstrøm er til at sende data
For at gøre streams 'håndgribelige' skrev Javas skabere to klasser: InputStream
og OutputStream
.
Klassen InputStream
har en read()
metode, der lader dig læse data fra den. Og OutputStream
klassen har en write()
metode, der lader dig skrive data til den. De har også andre metoder, men mere om det senere.
Byte-strømme
Hvilken slags data taler vi om? Hvilket format tager det? Med andre ord, hvilke datatyper understøtter disse klasser?
Disse er generiske klasser, så de understøtter den mest almindelige datatype - byte
. En OutputStream
kan skrive bytes (og byte-arrays), og et InputStream
objekt kan læse bytes (eller byte-arrays). Det er det - de understøtter ikke andre datatyper.
Som et resultat kaldes disse strømme også bytestrømme .
Et træk ved streams er, at deres data kun kan læses (eller skrives) sekventielt. Du kan ikke læse data fra midten af en strøm uden at læse alle de data, der kommer før den.
Sådan fungerer læsning af data fra tastaturet gennem Scanner
klassen: du læser data fra tastaturet sekventielt, linje for linje. Vi læser en linje, så den næste linje, så den næste linje og så videre. Metoden til at læse linjer hedder passende nok nextLine()
.
At skrive data til en OutputStream
sker også sekventielt. Et godt eksempel på dette er konsoludgang. Du udskriver en linje, efterfulgt af en og en anden. Dette er sekventielt output. Du kan ikke udskrive den første linje, derefter den tiende og derefter den anden. Alle data skrives kun sekventielt til en outputstrøm.
Karakterstrømme
Du har for nylig lært, at strenge er den næstmest populære datatype, og det er de faktisk. En masse information sendes rundt i form af tegn og hele strenge. En computer udmærker sig ved at sende og modtage alt som bytes, men mennesker er ikke så perfekte.
På grund af dette faktum skrev Java-programmører to klasser mere: Reader
og Writer
. Klassen Reader
er analog med InputStream
klassen, men dens read()
metode læser ikke bytes, men tegn ( char
). Klassen Writer
svarer til OutputStream
klassen. Og ligesom Reader
klassen fungerer den med tegn ( char
), ikke bytes.
Hvis vi sammenligner disse fire klasser, får vi følgende billede:
Bytes (byte) | Tegn (char) | |
---|---|---|
Læser data |
|
|
Skrivning af data |
|
|
Praktisk ansøgning
Selve InputStream
, OutputStream
, Reader
og Writer
klasserne bruges ikke direkte af nogen, da de ikke er forbundet med nogen konkrete objekter, hvorfra data kan læses (eller som data kan skrives ind). Men disse fire klasser har masser af efterkommerklasser, der kan meget.
2. InputStream
klasse
Klassen InputStream
er interessant, fordi den er forældreklassen for hundredvis af efterkommerklasser. Det har ingen egne data, men det har metoder, som alle dets afledte klasser arver.
Generelt er det sjældent, at stream-objekter gemmer data internt. En stream er et værktøj til at læse/skrive data, men ikke lagring. Når det er sagt, er der undtagelser.
Metoder for InputStream
klassen og alle dens efterkommerklasser:
Metoder | Beskrivelse |
---|---|
|
Læser én byte fra strømmen |
|
Læser en række bytes fra strømmen |
|
Læser alle bytes fra streamen |
|
Springer n bytes over i strømmen (læser og kasserer dem) |
|
Kontrollerer, hvor mange bytes der er tilbage i strømmen |
|
Lukker strømmen |
Lad os kort gennemgå disse metoder:
read()
metode
Metoden read()
læser en byte fra strømmen og returnerer den. Du kan blive forvirret over int
returtypen. Denne type blev valgt, fordi int
den er standard heltalstypen. De første tre bytes af int
vil være nul.
read(byte[] buffer)
metode
Dette er den anden variant af read()
metoden. Det lader dig læse en byte-array fra en InputStream
alt på én gang. Det array, der skal gemme bytes, skal sendes som et argument. Metoden returnerer et tal - antallet af bytes, der faktisk læses.
Lad os sige, at du har en buffer på 10 kilobyte, og du læser data fra en fil ved hjælp af FileInputStream
klassen. Hvis filen kun indeholder 2 kilobyte, vil alle data blive indlæst i bufferarrayet, og metoden returnerer tallet 2048 (2 kilobytes).
readAllBytes()
metode
En meget god metode. Det læser bare alle data fra InputStream
indtil det løber tør og returnerer det som et enkelt byte-array. Dette er meget praktisk til at læse små filer. Store filer passer muligvis ikke fysisk i hukommelsen, og metoden vil give en undtagelse.
skip(long n)
metode
Denne metode giver dig mulighed for at springe de første n bytes fra objektet InputStream
. Fordi dataene læses strengt sekventielt, læser denne metode simpelthen de første n bytes fra strømmen og kasserer dem.
Returnerer antallet af bytes, der faktisk blev sprunget over (i tilfælde af at streamen sluttede, før n
bytes blev sprunget over).
int available()
metode
Metoden returnerer antallet af bytes, der stadig er tilbage i strømmen
void close()
metode
Metoden close()
lukker datastrømmen og frigiver de eksterne ressourcer, der er knyttet til den. Når en strøm er lukket, kan der ikke læses flere data fra den.
Lad os skrive et eksempel på et program, der kopierer en meget stor fil. Vi kan ikke bruge readAllBytes()
metoden til at læse hele filen ind i hukommelsen. Eksempel:
Kode | Bemærk |
---|---|
|
InputStream til læsning fra filen OutputStream til skriv til fil Buffer, som vi vil læse dataene i Så længe der er data i strømmen Læs data ind i bufferen Skriv dataene fra bufferen til den anden strøm |
I dette eksempel brugte vi to klasser: FileInputStream
er en efterkommer af InputStream
til at læse data fra en fil, og FileOutputStream
er en efterkommer af OutputStream
til at skrive data til en fil. Vi vil tale om anden klasse lidt senere.
Et andet interessant punkt her er real
variablen. Når den sidste blok af data læses fra en fil, kan den nemt have mindre end 64 KB data. Derfor skal vi ikke udlæse hele bufferen, men kun en del af den - de første real
bytes. Det er præcis, hvad der sker i write()
metoden.
3. Reader
klasse
Klassen Reader
er en komplet analog af InputStream
klassen. Den eneste forskel er, at det fungerer med tegn ( char
), ikke med bytes. Ligesom InputStream
klassen Reader
bruges klassen ikke nogen steder alene: den er overordnet klasse for hundredvis af efterkommerklasser og definerer fælles metoder for dem alle.
Klassens metoder Reader
(og alle dens efterkommerklasser):
Metoder | Beskrivelse |
---|---|
|
Læser en char fra strømmen |
|
Læser et char array fra streamen |
|
Springer over n chars i strømmen (læser og kasserer dem) |
|
Tjek om der stadig er noget tilbage i streamen |
|
Lukker strømmen |
Metoderne minder meget om klassens metoder InputStream
, selvom der er små forskelle.
int read()
metode
Denne metode læser en char
fra strømmen og returnerer den. Typen char
udvides til en int
, men de første to bytes af resultatet er altid nul.
int read(char[] buffer)
metode
Dette er den anden variant af read()
metoden. Det lader dig læse et char-array fra en Reader
alt på én gang. Arrayet, der skal gemme tegnene, skal sendes som et argument. Metoden returnerer et tal - antallet af tegn, der faktisk læses.
skip(long n)
metode
Denne metode giver dig mulighed for at springe de første n tegn fra objektet Reader
. Det fungerer nøjagtigt det samme som den analoge metode i InputStream
klassen. Returnerer antallet af tegn, der faktisk blev sprunget over.
boolean ready()
metode
Returnerer true
, hvis der er ulæste bytes i strømmen.
void close()
metode
Metoden close()
lukker datastrømmen og frigiver de eksterne ressourcer, der er knyttet til den. Når en strøm er lukket, kan der ikke læses flere data fra den.
Til sammenligning, lad os skrive et program, der kopierer en tekstfil:
Kode | Bemærk |
---|---|
|
Reader til læsning fra en fil Writer til skrivning til en fil Buffer, hvori vi vil læse dataene Så længe der er data i strømmen Læs data i en buffer Skriv dataene fra bufferen til den anden strøm |