Guide de Java OutputStream

1. Vue d'ensemble

Dans ce didacticiel, nous explorerons les détails de la classe Java OutputStream . O utputStream est une classe abstraite. Cela sert de superclasse pour toutes les classes représentant un flux de sortie d'octets.

Nous examinerons ce que signifient ces mots comme «sortie» et «flux» plus en détail au fur et à mesure.

2. Brève introduction à Java IO

OutputStream fait partie de l'API Java IO qui définit les classes requises pour effectuer des opérations d'E / S en Java. Ceux-ci sont tous emballés dans l' espace de noms java.io. C'est l'un des packages principaux disponibles en Java depuis la version 1.0.

À partir de Java 1.4, nous avons également Java NIO emballé dans l'espace de noms java.nio qui permet des opérations d'entrée et de sortie non bloquantes. Cependant, notre domaine d'intérêt pour cet article est ObjectStream dans le cadre de Java IO.

Les détails relatifs à Java IO et Java NIO sont disponibles ici.

2.1. Entrée et sortie

Java IO fournit essentiellement un mécanisme pour lire des données à partir d'une source et écrire des données vers une destination . L'entrée représente la source tandis que la sortie représente la destination ici.

Ces sources et destinations peuvent être n'importe quoi, des fichiers, des tuyaux aux connexions réseau.

2.2. Ruisseaux

Java IO fournit le concept de flux qui représente essentiellement un flux continu de données . Les flux peuvent prendre en charge de nombreux types de données tels que des octets, des caractères, des objets, etc.

De plus, la connexion à une source ou à une destination est ce que représente un flux. Ils sont donc respectivement InputStream ou OutputStream .

3. Interfaces de OutputStream

OutputStream implémente un tas d'interfaces qui fournissent un caractère distinct à ses sous-classes. Passons en revue rapidement.

3.1. Fermable

L'interface Closeable fournit une méthode appelée close () qui gère la fermeture d'une source ou d'une destination de données. Chaque implémentation de OutputStream doit fournir une implémentation de cette méthode. Ici, ils peuvent effectuer des actions pour libérer des ressources.

3.2. Fermeture automatique

L'interface AutoCloseable fournit également une méthode appelée close () avec un comportement similaire à celui de Closeable . Dans ce cas, cependant, la méthode close () est automatiquement appelée lors de la sortie d'un bloc try-with-resource.

Vous trouverez plus de détails concernant l'essai avec la ressource ici.

3.3. Jetable

L'interface Flushable fournit une méthode appelée flush () qui gère le vidage des données vers une destination.

Une implémentation particulière de OutputStream peut choisir de mettre en mémoire tampon les octets précédemment écrits pour optimiser, mais un appel à flush () le fait immédiatement écrire sur la destination .

4. Méthodes dans OutputStream

OutputStream a plusieurs méthodes que chaque classe d'implémentation doit implémenter pour leurs types de données respectifs.

Ce sont en dehors des méthodes close () et flush () dont il hérite des interfaces Closeable et Flushable .

4.1. écrire (int b)

Nous pouvons utiliser cette méthode pour écrire un octet spécifique dans OutputStream . Puisque l'argument «int» comprend quatre octets, comme par le contrat, seul le premier octet de poids faible est écrit et les trois octets de poids fort restants sont ignorés:

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

Si nous appelons cette méthode avec des données comme "Hello World!", Ce que nous obtenons comme résultat est un fichier avec le texte suivant:

W

Ceci, comme nous pouvons le voir, est le septième caractère de la chaîne indexée sixième.

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

Cette version surchargée de la méthode write () est là pour écrire une sous-séquence du tableau d'octets dans OutputStream .

Il peut écrire un nombre «longueur» d'octets à partir du tableau d'octets comme spécifié par l'argument en commençant à un décalage déterminé par «off» dans 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); } }

Si nous appelons maintenant cette méthode avec les mêmes données qu'auparavant, nous obtenons le texte suivant dans notre fichier de sortie:

World

Il s'agit de la sous-chaîne de nos données commençant à l'index cinq et comprenant cinq caractères.

4.3. écrire (octet [] b)

Ceci est encore une autre version surchargée de la méthode write () qui peut écrire un tableau d'octets entier comme spécifié par l'argument de OutputStream .

Cela a le même effet qu'un appel à 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); } }

Lorsque nous appelons cette méthode maintenant avec les mêmes données, nous avons la chaîne entière dans notre fichier de sortie:

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); } }

Maintenant, comme nous pouvons le voir, nous n'avons pas à effectuer la transformation du tableau de caractères en tableau d'octets avant d'utiliser FileOutputStream. OutputStreamWriter fait cela pour nous .

Il n'est pas surprenant que lorsque nous appelons la méthode ci-dessus avec des données telles que "Hello World!", Cela se traduit par un fichier avec du texte comme:

Hello World!

8. Conclusion

Dans cet article, nous avons abordé la classe abstraite Java OutputStream . Nous avons parcouru les interfaces qu'il implémente et les méthodes qu'il fournit.

Ensuite, nous avons discuté de certaines des sous-classes de OutputStream disponibles en Java. Nous avons enfin parlé de mise en mémoire tampon et de flux de caractères.

Comme toujours, le code des exemples est disponible à l'adresse over sur GitHub.