Gids voor Java OutputStream

1. Overzicht

In deze zelfstudie verkennen we details over de Java-klasse OutputStream. OutputStream is een abstracte klasse. Dit dient als de superklasse voor alle klassen die een outputstroom van bytes vertegenwoordigen.

We zullen gaandeweg meer in detail onderzoeken wat deze woorden als "output" en "stream" betekenen.

2. Korte introductie tot Java IO

OutputStream is onderdeel van de Java IO API die klassen definieert die nodig zijn om I / O-bewerkingen in Java uit te voeren. Deze zijn allemaal verpakt in de java.io naamruimte. Dit is een van de kernpakketten die sinds versie 1.0 in Java beschikbaar zijn.

Vanaf Java 1.4 hebben we ook Java NIO verpakt in de naamruimte java.nio die niet-blokkerende invoer- en uitvoerbewerkingen mogelijk maakt. Ons aandachtsgebied voor dit artikel is echter ObjectStream als onderdeel van Java IO.

Details met betrekking tot Java IO en Java NIO zijn hier te vinden.

2.1. Input en output

Java IO biedt in feite een mechanisme om gegevens uit een bron te lezen en gegevens naar een bestemming te schrijven. Invoer vertegenwoordigt de bron, terwijl uitvoer hier de bestemming vertegenwoordigt.

Deze bronnen en bestemmingen kunnen van alles zijn, van bestanden, buizen tot netwerkverbindingen.

2.2. Streams

Java IO biedt het concept van stromen die in feite een continue stroom van gegevens vertegenwoordigen. Streams kunnen veel verschillende soorten gegevens ondersteunen, zoals bytes, tekens, objecten, enz.

Bovendien is verbinding met een bron of een bestemming wat een stream vertegenwoordigt. Ze komen dus als beide InputStream of OutputStream respectievelijk.

3. Interfaces van OutputStream

OutputStream implementeert een aantal interfaces die een bepaald karakter aan zijn subklassen geven. Laten we ze snel doornemen.

3.1. Afsluitbaar

De interface Afsluitbaar biedt een methode genaamd dichtbij() welke zorgt voor het sluiten van een bron of een bestemming van gegevens. Elke implementatie van OutputStream moet een implementatie van deze methode bieden. Hier kunnen ze acties uitvoeren om middelen vrij te geven.

3.2. AutoCloseable

De interface AutoCloseable biedt ook een methode genaamd dichtbij() met vergelijkbaar gedrag als in Afsluitbaar. In dit geval is het methode dichtbij() wordt automatisch aangeroepen bij het verlaten van een try-with-resource-blok.

Meer informatie over try-with-resource vindt u hier.

3.3. Doorspoelbaar

De interface Doorspoelbaar biedt een methode genaamd doorspoelen () die het doorspoelen van gegevens naar een bestemming afhandelt.

Een bijzondere implementatie van OutputStream kan ervoor kiezen om eerder geschreven bytes te bufferen om te optimaliseren, maar een oproep naar doorspoelen () zorgt ervoor dat het onmiddellijk naar de bestemming schrijft.

4. Methoden in OutputStream

OutputStream heeft verschillende methoden die elke implementatieklasse moet implementeren voor hun respectievelijke gegevenstypen.

Deze zijn afgezien van dichtbij() en doorspoelen () methoden waarvan het erft Afsluitbaar en Doorspoelbaar interfaces.

4.1. schrijf (int b)

We kunnen deze methode gebruiken om schrijf een specifieke byte naar het OutputStream. Aangezien het argument "int" vier bytes omvat, wordt als par het contract alleen de eerste byte van lage orde geschreven en de resterende drie bytes van hoge orde genegeerd:

openbare statische ongeldige fileOutputStreamByteSingle (String-bestand, String-gegevens) gooit IOException {byte [] bytes = data.getBytes (); probeer (OutputStream out = nieuwe FileOutputStream (bestand)) {out.write (bytes [6]); }}

Als we deze methode met gegevens "Hallo wereld!" Noemen, krijgen we als resultaat een bestand met de volgende tekst:

W.

Dit is, zoals we kunnen zien, het zevende teken van de als zesde geïndexeerde tekenreeks.

4.2. schrijven (byte [] b, int uit, int lengte)

Deze overbelaste versie van de schrijven() methode is er voor schrijf een subreeks van de byte-array naar de OutputStream.

Het kan het "lengte" aantal bytes uit de byte-array schrijven, zoals gespecificeerd door het argument, beginnend met een offset bepaald door "off" naar de Uitgangsstroom:

openbare statische ongeldige fileOutputStreamByteSubSequence (String-bestand, String-gegevens) gooit IOException {byte [] bytes = data.getBytes (); probeer (OutputStream out = nieuwe FileOutputStream (bestand)) {out.write (bytes, 6, 5); }}

Als we deze methode nu aanroepen met dezelfde gegevens als voorheen, krijgen we de volgende tekst in ons uitvoerbestand:

Wereld

Dit is de substring van onze gegevens, beginnend bij index vijf en bestaande uit vijf tekens.

4.3. schrijven (byte [] b)

Dit is weer een overbelaste versie van de schrijven() methode die kan schrijf een hele byte-array zoals gespecificeerd door het argument voor de OutputStream.

Dit heeft hetzelfde effect als een oproep naar schrijf (b, 0, b.lengh):

openbare statische ongeldige fileOutputStreamByteSequence (String-bestand, String-gegevens) gooit IOException {byte [] bytes = data.getBytes (); probeer (OutputStream out = nieuwe FileOutputStream (bestand)) {out.write (bytes); }}

Als we deze methode nu met dezelfde gegevens aanroepen, hebben we de volledige Draad in ons outputbestand:

Hallo Wereld!

5. Directe subklassen van OutputStream

Nu bespreken we enkele van de direct bekende subklassen van OutputStream die afzonderlijk een specifiek gegevenstype vertegenwoordigen waarvan de OutputStream ze definiëren.

Ze definiëren hun eigen methoden, afgezien van het implementeren van die welke zijn geërfd van OutputStream.

We zullen niet ingaan op de details van deze subklassen.

5.1. FileOutputStream

Zoals de naam suggereert, een FileOutputStream is een OutputStream om gegevens naar een het dossier. FileOutputStream, net als alle andere OutputStream, kan een stroom onbewerkte bytes schrijven.

We hebben al verschillende methoden onderzocht in FileOutputStream als onderdeel van de laatste sectie.

5.2. ByteArrayOutputStream

ByteArrayOutputStream is een invoer van OutputStream die gegevens in een byte-array kunnen schrijven. De buffer blijft groeien als ByteArrayOutputStream schrijft er gegevens naar toe.

We kunnen de standaard initiële grootte van de buffer behouden als 32 bytes of een specifieke grootte instellen met behulp van een van de beschikbare constructors.

Het belangrijkste om hier op te merken is dat de methode dichtbij() heeft praktisch geen effect. De andere methoden in ByteArrayOutputStream kan veilig worden gebeld, zelfs na dichtbij() is genoemd.

5.3. FilterOutputStream

OutputStream schrijft voornamelijk een bytestream naar een bestemming, maar het kan de gegevens net zo goed transformeren voordat ze dit doen. FilterOutputStream vertegenwoordigt superklasse van al dergelijke klassen die een specifieke gegevenstransformatie uitvoeren. FilterOutputStream wordt altijd gebouwd met een bestaand OutputStream.

Enkele voorbeelden van FilterOutputStream zijn BufferedOutputStream, CheckedOutputStream, CipherOutputStream, DataOutputStream, DeflaterOutputStream, DigestOutputStream, InflaterOutputStream, PrintStream.

5.4. ObjectOutputStream

ObjectOutputStream kan schrijf primitieve gegevenstypen en grafieken van Java-objecten naar een bestemming. We kunnen een ObjectOutputStream gebruikmakend van een bestaand OutputStream om naar een specifieke bestemming te schrijven, zoals Bestand.

Houd er rekening mee dat het noodzakelijk is om objecten te implementeren Serialiseerbaar voor ObjectOutputStream om ze naar een bestemming te schrijven. Meer informatie over Java-serialisering vindt u hier.

5.5. PipedOutputStream

EEN PipedOutputStream is handig om een ​​communicatiepijp te maken. PipedOutputStream kan gegevens schrijven die een aangesloten PipedInputStream kunnen lezen.

PipedOutputStream beschikt over een constructor om het te verbinden met een PipedInputStream. Als alternatief kunnen we dit later doen door een methode te gebruiken die in PipedOutputStream gebeld aansluiten().

6. OutputStream Bufferen

Bij invoer- en uitvoerbewerkingen zijn doorgaans relatief dure bewerkingen betrokken, zoals schijftoegang, netwerkactiviteit, enz. Als u dit vaak uitvoert, kan een programma minder efficiënt worden.

We hebben "gebufferde gegevensstromen" in Java om deze scenario's af te handelen. BufferedOutputStreamschrijft in plaats daarvan gegevens naar een buffer die minder vaak naar de bestemming wordt doorgespoeld, wanneer de buffer vol raakt, of de methode doorspoelen () wordt genoemd.

BufferedOutputStream strekt zich uit FilterOutputStream eerder besproken en verpakt een bestaand OutputStream om naar een bestemming te schrijven:

public static void bufferedOutputStream (String file, String ... data) gooit IOException {try (BufferedOutputStream out = new BufferedOutputStream (new FileOutputStream (file))) {voor (String s: data) {out.write (s.getBytes () ); out.write ("" .getBytes ()); }}}

Het kritische punt om op te merken is dat elke oproep naar schrijven() voor elk data-argument schrijft alleen naar de buffer en resulteert niet in een potentieel dure aanroep naar het bestand.

Als we in het bovenstaande geval deze methode aanroepen met gegevens als "Hallo", "Wereld!", Zal dit alleen resulteren in het schrijven van gegevens naar het bestand wanneer de code het try-with-resources-blok verlaat dat de methode aanroept dichtbij() op de BufferedOutputStream.

Dit resulteert in een uitvoerbestand met de volgende tekst:

Hallo Wereld!

7. Tekst schrijven met OutputStreamWriter

Een bytestroom, zoals eerder besproken, vertegenwoordigt onbewerkte gegevens die een aantal teksttekens kunnen zijn. Nu kunnen we de character-array ophalen en de conversie naar de byte-array zelf uitvoeren:

byte [] bytes = data.getBytes ();

Java biedt handige klassen om deze kloof te overbruggen. Voor het geval van OutputStream, deze klasse is OutputStreamWriter. OutputStreamWriter wikkelt een OutputStream en kan karakters direct naar de gewenste bestemming schrijven.

Optioneel kunnen we ook de OutputStreamWriter met een tekenset voor codering:

openbare statische ongeldige outputStreamWriter (String-bestand, String-gegevens) gooit IOException {try (OutputStream out = nieuwe FileOutputStream (bestand); Writer-schrijver = nieuwe OutputStreamWriter (uit, "UTF-8")) {writer.write (gegevens); }}

Zoals we kunnen zien, hoeven we de transformatie van de tekenreeks naar de bytearray niet uit te voeren voordat we deze gebruiken FileOutputStream.OutputStreamWriter doet dit handig voor ons.

Het is niet verrassend dat wanneer we de bovenstaande methode aanroepen met gegevens als "Hallo wereld!", Dit resulteert in een bestand met tekst als:

Hallo Wereld!

8. Conclusie

In dit artikel hebben we de Java-abstracte klasse besproken OutputStream. We hebben de interfaces die het implementeert en de methoden die het biedt doorgenomen.

Vervolgens bespraken we enkele van de subklassen van OutputStream beschikbaar in Java. We hadden het eindelijk over buffering en personagestreams.

Zoals altijd is de code voor de voorbeelden beschikbaar op GitHub.