Anleitung zu Java OutputStream

1. Übersicht

In diesem Tutorial werden Details zur Java-Klasse OutputStream erläutert . O utputStream ist eine abstrakte Klasse. Dies dient als Oberklasse für alle Klassen, die einen Ausgabestrom von Bytes darstellen.

Wir werden untersuchen, was diese Wörter wie "Ausgabe" und "Stream" im weiteren Verlauf genauer bedeuten.

2. Kurze Einführung in Java IO

OutputStream ist Teil der Java- E / A- API, die Klassen definiert, die zum Ausführen von E / A-Operationen in Java erforderlich sind. Diese sind alle im Namespace java.io gepackt . Dies ist eines der Kernpakete, die seit Version 1.0 in Java verfügbar sind.

Ab Java 1.4 haben wir auch Java NIO im Namespace java.nio gepackt , das nicht blockierende Eingabe- und Ausgabeoperationen ermöglicht. Unser Schwerpunkt für diesen Artikel ist jedoch ObjectStream als Teil von Java IO.

Details zu Java IO und Java NIO finden Sie hier.

2.1. Ein- und Ausgabe

Java IO bietet grundsätzlich einen Mechanismus zum Lesen von Daten aus einer Quelle und zum Schreiben von Daten in ein Ziel . Die Eingabe stellt die Quelle dar, während die Ausgabe hier das Ziel darstellt.

Diese Quellen und Ziele können von Dateien, Pipes bis hin zu Netzwerkverbindungen reichen.

2.2. Streams

Java IO bietet das Konzept von Streams, die im Wesentlichen einen kontinuierlichen Datenfluss darstellen . Streams können viele verschiedene Datentypen wie Bytes, Zeichen, Objekte usw. unterstützen.

Darüber hinaus ist die Verbindung zu einer Quelle oder einem Ziel das, was ein Stream darstellt. Sie kommen daher entweder als InputStream bzw. OutputStream .

3. Schnittstellen von OutputStream

OutputStream implementiert eine Reihe von Schnittstellen, die den Unterklassen einen bestimmten Charakter verleihen . Lassen Sie uns sie schnell durchgehen.

3.1. Verschließbar

Die Schnittstelle Closeable bietet eine Methode namens close (), mit der eine Quelle oder ein Ziel von Daten geschlossen werden kann. Jede Implementierung von OutputStream muss eine Implementierung dieser Methode bereitstellen. Hier können sie Aktionen ausführen, um Ressourcen freizugeben.

3.2. AutoCloseable

Die Schnittstelle AutoCloseable bietet auch eine Methode namens close () mit einem ähnlichen Verhalten wie in Closeable . In diesem Fall wird die Methode close () jedoch automatisch aufgerufen, wenn ein Try-with-Resource-Block beendet wird.

Weitere Details zum Try-with-Resource finden Sie hier.

3.3. Spülbar

Die Schnittstelle Flushable bietet eine Methode namens flush (), mit der Daten an ein Ziel gespült werden .

Eine bestimmte Implementierung von OutputStream kann sich dafür entscheiden, zuvor geschriebene Bytes zu puffern, um sie zu optimieren. Bei einem Aufruf von flush () wird sie jedoch sofort in das Ziel geschrieben .

4. Methoden in OutputStream

OutputStream verfügt über mehrere Methoden, die jede implementierende Klasse für ihren jeweiligen Datentyp implementieren muss.

Dies sind abgesehen von den Methoden close () und flush () , die von den Schnittstellen Closeable und Flushable geerbt werden.

4.1. schreibe (int b)

Mit dieser Methode können wir ein bestimmtes Byte in den OutputStream schreiben . Da das Argument "int" vier Bytes umfasst, wird als Vertrag nur das erste Byte niedriger Ordnung geschrieben und die verbleibenden drei Bytes hoher Ordnung ignoriert:

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

Wenn wir diese Methode mit Daten als "Hallo Welt!" Aufrufen, erhalten wir als Ergebnis eine Datei mit dem folgenden Text:

W

Wie wir sehen können, ist dies das siebte Zeichen der als sechstes indizierten Zeichenfolge.

4.2. Schreiben (Byte [] b, int aus, int Länge)

Diese überladene Version der write () -Methode dient dazu , eine Teilsequenz des Byte-Arrays in den OutputStream zu schreiben .

Es kann die Anzahl der Bytes "Länge" aus dem Byte-Array schreiben, wie durch das Argument angegeben, beginnend mit einem durch "Aus" bestimmten Offset in den 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); } }

Wenn wir diese Methode jetzt mit denselben Daten wie zuvor aufrufen, erhalten wir den folgenden Text in unserer Ausgabedatei:

World

Dies ist die Teilzeichenfolge unserer Daten, die bei Index fünf beginnt und fünf Zeichen umfasst.

4.3. Schreiben (Byte [] b)

Dies ist eine weitere überladene Version der write () -Methode, die ein ganzes Byte-Array schreiben kann , wie im Argument für den OutputStream angegeben .

Dies hat den gleichen Effekt wie ein Aufruf zum Schreiben (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); } }

Wenn wir diese Methode jetzt mit denselben Daten aufrufen, haben wir den gesamten String in unserer Ausgabedatei:

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

Wie wir jetzt sehen können, müssen wir die Umwandlung des Zeichenarrays in das Bytearray nicht durchführen, bevor wir FileOutputStream verwenden. OutputStreamWriter erledigt dies bequem für uns .

Es überrascht nicht, dass beim Aufrufen der obigen Methode mit Daten wie „Hello World!“ Eine Datei mit dem folgenden Text erstellt wird:

Hello World!

8. Fazit

In diesem Artikel haben wir die abstrakte Java-Klasse OutputStream behandelt . Wir haben die implementierten Schnittstellen und die darin enthaltenen Methoden durchgesehen.

Anschließend haben wir einige der in Java verfügbaren Unterklassen von OutputStream besprochen . Wir haben schließlich über Pufferung und Zeichenströme gesprochen.

Wie immer ist der Code für die Beispiele auf GitHub verfügbar.