1. Overview
We often work with OutputStream when we need to transfer data to external destinations such as files and networks. Data can either be in binary or string format. We use OutputStream, which is a byte stream, to deal with binary data, and Writer, which is a character stream, to deal with string data.
However, there are situations where we have to write strings into an OutputStream due to the limitations imposed by the selected API. In some instances, the API may only provide OutputStream instead of Writer. In this tutorial, we’ll explore different methods for writing strings into OutputStream in such scenarios.
2. Byte Conversion
The most intuitive approach involves converting the string into bytes and then writing the converted bytes into the OutputStream:
String str = "Hello";
byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
outputStream.write(bytes);
This approach is straightforward but has a major drawback. We need to explicitly convert the string into bytes beforehand and specify the character encoding each time when calling getBytes(). This makes our code cumbersome.
3. OutputStreamWriter
A better approach is to utilize OutputStreamWriter to wrap our OutputStream. OutputStreamWriter serves as a wrapper that transforms a character stream into a byte stream. Strings written to it are encoded into bytes using the chosen character encoding.
We write the string via the write() method without specifying the character encoding. Each invocation of write() on OutputStreamWriter implicitly converts the string into encoded bytes, providing a more streamlined process:
try (OutputStreamWriter writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8)) {
writer.write("Hello");
}
If the wrapped OutputStream is not yet buffered, we advise using the BufferedWriter to wrap around the OutputStreamWriter to make the writing process more efficient:
BufferedWriter bufferedWriter = new BufferedWriter(writer);
This reduces IO operations by first writing data to a buffer and then flushing the buffered data to the stream in a larger chunk.
4. PrintStream
Another option is to utilize PrintStream, which provides functionality similar to OutputStreamWriter. Similar to OutputStreamWriter, we can specify the encoding when we instantiate PrintStream:
try (PrintStream printStream = new PrintStream(outputStream, true, StandardCharsets.UTF_8)) {
printStream.print("Hello");
}
If we don’t define the character encoding explicitly in the constructor, the default encoding will be UTF-8:
PrintStream printStream = new PrintStream(outputStream);
The difference between PrintStream and OutputStreamWriter is that PrintStream provides additional print() methods for writing different data types to the OutputStream. Also, PrintWriter never throws an IOException for its print() and write() methods:
printStream.print(100); // integer
printStream.print(true); // boolean
5. PrintWriter
PrintWriter serves a similar purpose to PrintStream, offering functionality for writing formatted representations of data to an OutputStream:
try (PrintWriter writer = new PrintWriter(outputStream)) {
writer.print("Hello");
}
Besides wrapping OutputStream, PrintWriter provides additional constructors to wrap Writer as well. Another difference between them is that PrintWriter provides write() methods for writing character arrays, whereas PrintStream provides write() methods for writing byte arrays:
char[] c = new char[] {'H', 'e', 'l' ,'l', 'o'};
try (PrintWriter writer = new PrintWriter(new StringWriter())) {
writer.write(c);
}
6. Conclusion
In this article, we’ve explored several approaches for writing strings to an OutputStream in Java.
We began with the straightforward conversion of strings into bytes, which requires explicit encoding for each write operation and impacts the code’s maintainability. Subsequently, we explored three different Java classes that wrap around the OutputStream to encode strings into bytes seamlessly.
As always, the sample code is available over on GitHub.