Guida a Java OutputStream

1. Panoramica

In questo tutorial, esploreremo i dettagli sulla classe Java OutputStream . O utputStream è una classe astratta. Questa funge da superclasse per tutte le classi che rappresentano un flusso di output di byte.

Esamineremo il significato di queste parole come "output" e "stream" in maggiore dettaglio man mano che procediamo.

2. Breve introduzione a Java IO

OutputStream fa parte dell'API IO Java che definisce le classi richieste per eseguire operazioni di I / O in Java. Questi sono tutti impacchettati nello spazio dei nomi java.io. Questo è uno dei pacchetti principali disponibili in Java dalla versione 1.0.

A partire da Java 1.4, abbiamo anche Java NIO impacchettato nello spazio dei nomi java.nio che consente operazioni di input e output non bloccanti. La nostra area di interesse per questo articolo, tuttavia, è ObjectStream come parte di Java IO.

I dettagli relativi a Java IO e Java NIO possono essere trovati qui.

2.1. Ingresso e uscita

Java IO fornisce fondamentalmente un meccanismo per leggere i dati da un'origine e scrivere dati in una destinazione . Input rappresenta la sorgente mentre output rappresenta la destinazione qui.

Queste origini e destinazioni possono essere qualsiasi cosa, da file, pipe a connessioni di rete.

2.2. Flussi

Java IO fornisce il concetto di flussi che sostanzialmente rappresenta un flusso continuo di dati . I flussi possono supportare molti diversi tipi di dati come byte, caratteri, oggetti, ecc.

Inoltre, la connessione a una sorgente o una destinazione è ciò che rappresenta un flusso. Vengono quindi rispettivamente come InputStream o OutputStream .

3. Interfacce di OutputStream

OutputStream implementa una serie di interfacce che forniscono un carattere distinto alle sue sottoclassi. Esaminiamoli rapidamente.

3.1. Chiudibile

L'interfaccia Closeable fornisce un metodo chiamato close () che gestisce la chiusura di un'origine o di una destinazione di dati. Ogni implementazione di OutputStream deve fornire un'implementazione di questo metodo. Qui possono eseguire azioni per rilasciare risorse.

3.2. Autochiudibile

L'interfaccia AutoCloseable fornisce anche un metodo chiamato close () con un comportamento simile a quello di Closeable . In questo caso, tuttavia, il metodo close () viene chiamato automaticamente quando si esce da un blocco try-with-resource.

Maggiori dettagli sulla prova con la risorsa sono disponibili qui.

3.3. Flushable

L'interfaccia Flushable fornisce un metodo chiamato flush () che gestisce lo scaricamento dei dati in una destinazione.

Una particolare implementazione di OutputStream può scegliere di memorizzare nel buffer i byte scritti in precedenza per ottimizzare, ma una chiamata a flush () lo fa scrivere immediatamente nella destinazione .

4. Metodi in OutputStream

OutputStream ha diversi metodi che ogni classe di implementazione deve implementare per i rispettivi tipi di dati.

Questi sono diversi dai metodi close () e flush () che eredita dalle interfacce Closeable e Flushable .

4.1. scrivi (int b)

Possiamo usare questo metodo per scrivere un byte specifico in OutputStream . Poiché l'argomento "int" comprende quattro byte, per il contratto viene scritto solo il primo byte di ordine inferiore e vengono ignorati i restanti tre byte di ordine elevato:

public static void fileOutputStreamByteSingle(String file, String data) throws IOException { byte[] bytes = data.getBytes(); try (OutputStream out = new FileOutputStream(file)) { out.write(bytes[6]); } }

Se chiamiamo questo metodo con i dati come "Hello World!", Ciò che otteniamo come risultato è un file con il seguente testo:

W

Questo, come possiamo vedere, è il settimo carattere della sesta stringa indicizzata.

4.2. scrivi (byte [] b, int off, int length)

Questa versione sovraccaricata del metodo write () serve a scrivere una sottosequenza dell'array di byte in OutputStream .

It can write “length” number of bytes from the byte array as specified by the argument starting at an offset determined by “off” to the OutputStream:

public static void fileOutputStreamByteSubSequence( String file, String data) throws IOException { byte[] bytes = data.getBytes(); try (OutputStream out = new FileOutputStream(file)) { out.write(bytes, 6, 5); } }

If we now call this method with the same data as before, we get the following text in our output file:

World

This is the substring of our data starting at index five and comprising five characters.

4.3. write(byte[] b)

This is yet another overloaded version of the write() method which can write an entire byte array as specified by the argument to the OutputStream.

This has the same effect as a call to write(b, 0, b.lengh):

public static void fileOutputStreamByteSequence(String file, String data) throws IOException { byte[] bytes = data.getBytes(); try (OutputStream out = new FileOutputStream(file)) { out.write(bytes); } }

When we call this method now with the same data, we have the entire String in our output file:

Hello World!

5. Direct Subclasses of OutputStream

Now we'll discuss some of the direct known subclasses of OutputStream which individually represent a specific data type of which the OutputStream they define.

They define their own methods apart from implementing those inherited from OutputStream.

We won't go into the details of these subclasses.

5.1. FileOutputStream

As the name suggests, a FileOutputStream is an OutputStream to write data to a File. FileOutputStream, like any other OutputStream, can write a stream of raw bytes.

We have already examined different methods in FileOutputStream as part of the last section.

5.2. ByteArrayOutputStream

ByteArrayOutputStream is an implementation of OutputStream that can write data into a byte array. The buffer keeps growing as ByteArrayOutputStream writes data to it.

We can keep the default initial size of the buffer as 32 bytes or set a specific size using one of the constructors available.

The important thing to note here is that the method close() has practically no effect. The other methods in ByteArrayOutputStream can be safely called even after close() has been called.

5.3. FilterOutputStream

OutputStream primarily writes a byte stream to a destination, but it can as well transform the data before doing so. FilterOutputStream represents superclass of all such classes which perform a specific data transformation. FilterOutputStream is always constructed with an existing OutputStream.

Some of the examples of FilterOutputStream are BufferedOutputStream, CheckedOutputStream, CipherOutputStream, DataOutputStream, DeflaterOutputStream, DigestOutputStream, InflaterOutputStream, PrintStream.

5.4. ObjectOutputStream

ObjectOutputStream can write primitive data types and graphs of Java objects to a destination. We can construct an ObjectOutputStream using an existing OutputStream to write to a specific destination like File.

Please note that it is necessary for objects to implement Serializable for ObjectOutputStream to write them to a destination. You can find more details on Java Serialization here.

5.5. PipedOutputStream

A PipedOutputStream is useful to create a communication pipe. PipedOutputStream can write data which a connected PipedInputStream can read.

PipedOutputStream features a constructor to connect it with a PipedInputStream. Alternatively, we can do this later by using a method provided in PipedOutputStream called connect().

6. OutputStream Buffering

Input and output operations typically involve relatively expensive operations like disk access, network activity, etc. Performing this often can make a program less efficient.

We have “buffered streams” of data in Java to handle these scenarios. BufferedOutputStreamwrites data to a buffer instead which is flushed to the destination less often, when the buffer gets full, or the method flush() is called.

BufferedOutputStream extends FilterOutputStream discussed earlier and wraps an existing OutputStream to write to a destination:

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

The critical point to note is that every call to write() for each data argument only writes to the buffer and does not result in a potentially expensive call to the File.

In the case above, if we call this method with data as “Hello”, “World!”, this will only result in data being written to the File when the code exits from the try-with-resources block which calls the method close() on the BufferedOutputStream.

This results in an output file with the following text:

Hello World!

7. Writing Text with OutputStreamWriter

A byte stream, as discussed earlier, represents raw data which may be a bunch of text characters. Now we can get the character array and perform the conversion to the byte array ourselves:

byte[] bytes = data.getBytes();

Java provides convenient classes to bridge this gap. For the case of OutputStream, this class is OutputStreamWriter. OutputStreamWriter wraps an OutputStream and can directly write characters to the desired destination.

We can also optionally provide the OutputStreamWriter with a character set for encoding:

public static void outputStreamWriter(String file, String data) throws IOException { try (OutputStream out = new FileOutputStream(file); Writer writer = new OutputStreamWriter(out,"UTF-8")) { writer.write(data); } }

Ora, come possiamo vedere, non è necessario eseguire la trasformazione dell'array di caratteri nell'array di byte prima di utilizzare FileOutputStream. OutputStreamWriter lo fa comodamente per noi .

Non sorprende che quando chiamiamo il metodo sopra con dati come "Hello World!", Questo si traduce in un file con testo come:

Hello World!

8. Conclusione

In questo articolo, abbiamo discusso la classe astratta Java OutputStream . Abbiamo esaminato le interfacce che implementa e i metodi che fornisce.

Quindi abbiamo discusso alcune delle sottoclassi di OutputStream disponibili in Java. Abbiamo finalmente parlato di buffering e flussi di personaggi.

Come sempre, il codice per gli esempi è disponibile su GitHub.