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 Scannerobjekt - 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: InputStreamog OutputStream.

Klassen InputStreamhar en read()metode, der lader dig læse data fra den. Og OutputStreamklassen 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 OutputStreamkan skrive bytes (og byte-arrays), og et InputStreamobjekt 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 Scannerklassen: 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 OutputStreamsker 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: Readerog Writer. Klassen Readerer analog med InputStreamklassen, men dens read()metode læser ikke bytes, men tegn ( char). Klassen Writersvarer til OutputStreamklassen. Og ligesom Readerklassen 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
InputStream
Reader
Skrivning af data
OutputStream
Writer

Praktisk ansøgning

Selve InputStream, OutputStream, Readerog Writerklasserne 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. InputStreamklasse

Klassen InputStreamer 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 InputStreamklassen og alle dens efterkommerklasser:

Metoder Beskrivelse
int read()
Læser én byte fra strømmen
int read(byte[] buffer)
Læser en række bytes fra strømmen
byte[] readAllBytes()
Læser alle bytes fra streamen
long skip(long n)
Springer nbytes over i strømmen (læser og kasserer dem)
int available()
Kontrollerer, hvor mange bytes der er tilbage i strømmen
void close()
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 intreturtypen. Denne type blev valgt, fordi intden er standard heltalstypen. De første tre bytes af intvil 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 InputStreamalt 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 FileInputStreamklassen. 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 InputStreamindtil 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 nbytes 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
String src = "c:\\projects\\log.txt";
String dest = "c:\\projects\\copy.txt";

try(FileInputStream input = new FileInputStream(src);
FileOutputStream output = new FileOutputStream(dest))
{
   byte[] buffer = new byte[65536]; // 64Kb
   while (input.available() > 0)
   {
      int real = input.read(buffer);
      output.write(buffer, 0, real);
   }
}



InputStreamtil læsning fra filen
OutputStreamtil 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: FileInputStreamer en efterkommer af InputStreamtil at læse data fra en fil, og FileOutputStreamer en efterkommer af OutputStreamtil at skrive data til en fil. Vi vil tale om anden klasse lidt senere.

Et andet interessant punkt her er realvariablen. 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 realbytes. Det er præcis, hvad der sker i write()metoden.



3. Readerklasse

Klassen Readerer en komplet analog af InputStreamklassen. Den eneste forskel er, at det fungerer med tegn ( char), ikke med bytes. Ligesom InputStreamklassen Readerbruges 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
int read()
Læser en charfra strømmen
int read(char[] buffer)
Læser et chararray fra streamen
long skip(long n)
Springer over n charsi strømmen (læser og kasserer dem)
boolean ready()
Tjek om der stadig er noget tilbage i streamen
void close()
Lukker strømmen

Metoderne minder meget om klassens metoder InputStream, selvom der er små forskelle.

int read()metode

Denne metode læser en charfra strømmen og returnerer den. Typen charudvides 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 Readeralt 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 InputStreamklassen. 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
String src = "c:\\projects\\log.txt";
String dest = "c:\\projects\\copy.txt";

try(FileReader reader = new FileReader(src);
FileWriter writer = new FileWriter(dest))
{
   char[] buffer = new char[65536]; // 128Kb
   while (reader.ready())
   {
      int real = reader.read(buffer);
      writer.write(buffer, 0, real);
   }
}



Readertil læsning fra en fil
Writertil 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