Guide de Java OutputStream

1. Vue d’ensemble

Dans ce didacticiel, nous allons explorer les détails de la classe Java OutputStream . OutputStream est une classe abstraite. Cela sert de la super-classe pour toutes les classes représentant un flux de sortie d’octets.

Nous examinerons la signification de ces mots tels que "sortie" et "flux" au fur et à mesure que nous avançons.

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. Celles-ci sont toutes regroupées dans l’espace de noms java.io . C’est l’un des principaux packages disponibles en Java depuis la version 1.0.

À partir de Java 1.4, Java NIO est également inclus dans l’espace de noms java.nio , ce qui permet des opérations d’entrée et de sortie non bloquantes. Cependant, notre domaine d’intervention pour cet article est ObjectStream dans le cadre de Java IO.

Des informations détaillées sur Java IO et Java NIO sont disponibles à l’adresse here .

2.1. Entrée et sortie

Java IO fournit fondamentalement un mécanisme pour lire les données d’une source et écrire des données dans 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 canaux aux connexions réseau.

2.2. Ruisseaux

Java IO fournit le concept de flux qui représente fondamentalement 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 se présentent donc sous la forme InputStream ou OutputStream respectivement.

3. Interfaces de OutputStream

OutputStream implémente un ensemble d’interfaces qui fournissent un caractère distinct à ses sous-classes. Voyons-les rapidement.

3.1. Fermable

L’interface Closeable fournit une méthode appelée _close () which 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. AutoCloseable

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 sur try-with-resource à l’adresse https://www.baeldung.com/java-try-with-resources [here.

3.3. Flushable

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 à optimiser, mais un appel à flush () le fait écrire immédiatement dans 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. write (int b)

Nous pouvons utiliser cette méthode pour écrire un octet spécifique dans OutputStream . Puisque l’argument «int» comprend quatre octets, 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 les données «Hello World!», Nous obtenons un fichier contenant le texte suivant:

W

Comme nous pouvons le constater, il s’agit du septième caractère de la chaîne indexée sixième.

4.2. write (octet[]b, int off, int longueur)

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 «longueur» nombre d’octets à partir du tableau d’octets, comme spécifié par l’argument commençant par un décalage déterminé par «off» dans le 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 que précédemment, nous obtenons le texte suivant dans notre fichier de sortie:

World

C’est la sous-chaîne de nos données commençant à l’index cinq et comprenant cinq caractères.

4.3. write (byte[]b)

C’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 avec les mêmes données, nous avons l’intégralité de la chaîne String dans notre fichier de sortie:

Hello World!

5. Sous-classes directes de OutputStream

Nous allons maintenant aborder certaines des sous-classes directes connues de OutputStream qui représentent individuellement un type de données spécifique dont ils définissent le OutputStream .

Ils définissent leurs propres méthodes en dehors de celles implémentées de celles héritées de OutputStream .

Nous n’entrerons pas dans les détails de ces sous-classes.

5.1. FileOutputStream

Comme son nom l’indique, un FileOutputStream est un OutputStream pour écrire des données dans un _file . FileOutputStream, comme tout autre OutputStream_, peut écrire un flux d’octets bruts.

Nous avons déjà examiné différentes méthodes dans FileOutputStream dans le cadre de la dernière section.

5.2. ByteArrayOutputStream

ByteArrayOutputStream est une implémentation de OutputStream pouvant écrire des données dans un tableau d’octets . La mémoire tampon continue de croître au fur et à mesure que ByteArrayOutputStream y écrit des données.

Nous pouvons conserver la taille initiale du tampon par défaut de 32 octets ou définir une taille spécifique en utilisant l’un des constructeurs disponibles.

La chose importante à noter ici est que la méthode close () n’a pratiquement aucun effet. Les autres méthodes de ByteArrayOutputStream peuvent être appelées en toute sécurité même après l’appel de close () .

5.3. FilterOutputStream

OutputStream écrit principalement un flux d’octets sur une destination, mais il peut également transformer les données avant de le faire. FilterOutputStream représente la superclasse de toutes ces classes qui effectuent une transformation de données spécifique . FilterOutputStream est toujours construit avec un OutputStream existant.

Certains des exemples de FilterOutputStream sont BufferedOutputStream , CheckedOutputStream , CipherOutputStream , DataOutputStream , DeflaterOutputStream , CipherOutputStream , DataigutOutputStream , __InflaterOutlet

5.4. ObjectOutputStream

ObjectOutputStream peut écrire des types de données primitifs et des graphiques d’objets Java vers une destination. Nous pouvons construire un ObjectOutputStream en utilisant un OutputStream existant pour écrire dans une destination spécifique telle que Fichier.

Notez que les objets doivent implémenter Serializable pour que ObjectOutputStream les écrive dans une destination. Vous pouvez trouver plus de détails sur la sérialisation Java à l’adresse here .

5.5. PipedOutputStream

Un PipedOutputStream est utile pour créer un canal de communication .

PipedOutputStream peut écrire des données qu’un PipedInputStream connecté peut lire.

PipedOutputStream dispose d’un constructeur pour le connecter avec un PipedInputStream . Sinon, nous pouvons le faire plus tard en utilisant une méthode fournie dans PipedOutputStream appelée connect () .

6. Mise en mémoire tampon OutputStream

Les opérations d’entrée et de sortie impliquent généralement des opérations relativement coûteuses telles que l’accès au disque, l’activité du réseau, etc. L’exécution de cette opération peut souvent rendre un programme moins efficace.

Nous avons des «flux tamponnés» de données en Java pour gérer ces scénarios.

BufferedOutputStream écrit des données dans un tampon qui est vidé moins souvent vers la destination , lorsque le tampon est plein ou que la méthode flush () est appelée.

BufferedOutputStream étend FilterOutputStream discuté précédemment et encapsule un _OutputStream _ existant pour écrire dans une 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());
        }
    }
}

Le point critique à noter est que chaque appel à write () pour chaque argument de données écrit uniquement dans le tampon et n’entraîne pas un appel potentiellement coûteux au fichier.

Dans le cas ci-dessus, si nous appelons cette méthode avec les données «Hello», «World!», Les données ne seront écrites dans le fichier que lorsque le code quittera le bloc try-with-resources qui appelle la méthode close () sur le BufferedOutputStream .

Cela donne un fichier de sortie avec le texte suivant:

Hello World!

7. Écrire du texte avec OutputStreamWriter

Comme indiqué précédemment, un flux d’octets représente des données brutes qui peuvent être un groupe de caractères de texte. Maintenant, nous pouvons obtenir le tableau de caractères et effectuer la conversion en tableau d’octets nous-mêmes:

byte[]bytes = data.getBytes();

Java fournit des classes pratiques pour combler cet écart. Dans le cas de OutputStream , cette classe est OutputStreamWriter .

  • OutputStreamWriter encapsule un OutputStream et peut directement écrire des caractères dans la destination souhaitée ** .

Nous pouvons également éventuellement fournir le __OutputStreamWriter __with un jeu de caractères pour le codage:

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

Comme nous pouvons le constater, il n’est pas nécessaire de transformer le tableau de caractères en tableau d’octets avant d’utiliser FileOutputStream. OutputStreamWriter le fait commodément pour nous __ .

Sans surprise, lorsque nous appelons la méthode ci-dessus avec des données telles que «Hello World!», Il en résulte un fichier avec le texte suivant:

Hello World!

8. Conclusion

Dans cet article, nous avons abordé la classe abstraite Java OutputStream . Nous avons examiné les interfaces implémentées et les méthodes fournies.

Nous avons ensuite abordé certaines des sous-classes de OutputStream disponibles en Java. Nous avons finalement parlé de la mise en mémoire tampon et des flux de caractères.

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