Back to Blog
Java

Java Writer: A Practical Guide to Character Streams

java writer: Learn how to use Java's Writer class for character output, including FileWriter, BufferedWriter, and OutputStreamWriter with practical examples.

JavaWriterFileWriterBufferedWriterOutputStreamWriterCharacter Streams
Illustration of Java Writer class hierarchy and character stream writing to a file.

java writer requires a clear understanding of the core syntax, runtime behavior, and practical implementation patterns demonstrated in the examples below.

What Is java.io.Writer?

The Writer class in java.io is the abstract base class for all character output streams. Unlike OutputStream, which writes raw bytes, Writer writes characters using a specific character encoding. This distinction matters when you are producing text files, HTML, JSON, or any human-readable output. The class provides methods for writing strings, character arrays, and single characters, and it supports automatic flushing and closing.

Core Methods of Writer

The Writer class defines several abstract and concrete methods. The most important are write(int c), write(char[] cbuf), write(String str), and flush(). The write methods are overloaded to accept offsets and lengths. For example, write(char[] cbuf, int off, int len) writes a portion of a character array. All write methods eventually delegate to the abstract write(char[] cbuf, int off, int len), which subclasses must implement.

Writer writer = new FileWriter("output.txt"); writer.write("Hello, "); writer.write(new char[] {'W', 'o', 'r', 'l', 'd'}); writer.flush(); writer.close();

Common Writer Subclasses

Java provides several concrete implementations of Writer for different destinations. FileWriter writes to a file, StringWriter accumulates characters in a string buffer, and OutputStreamWriter bridges a byte stream to a character stream. BufferedWriter adds buffering to any other Writer, reducing the number of underlying I/O operations. Each subclass serves a distinct purpose, and choosing the right one depends on your output target and performance needs.

Writing to Files with FileWriter

FileWriter is the simplest way to write text to a file. It opens a file and writes characters using the platform's default charset unless you specify one. For example, new FileWriter("notes.txt") creates or truncates the file. To append, pass true as the second argument. Because FileWriter directly writes to the file system, each write call may trigger a system call, which can be slow for many small writes.

try (FileWriter writer = new FileWriter("log.txt", true)) { writer.write("New log entry\n"); }

Buffering Output with BufferedWriter

When you need to write many small pieces of text, wrapping a Writer in a BufferedWriter reduces the number of I/O operations. The buffer accumulates characters and flushes them to the underlying writer only when it is full or when flush() is called. This is particularly effective when writing to a file or a network socket. The pattern is simple: wrap your target writer and use the buffered instance.

try (BufferedWriter writer = new BufferedWriter(new FileWriter("large.txt"))) { for (int i = 0; i < 1000; i++) { writer.write("Line " + i + "\n"); } }

Handling Character Encoding with OutputStreamWriter

OutputStreamWriter is a bridge between byte streams and character streams. It takes an OutputStream and a charset, allowing you to control the encoding explicitly. This is essential when you need to produce UTF-8 files or when the platform's default charset is not appropriate. For example, to write UTF-8 encoded text to a file, you can combine FileOutputStream and OutputStreamWriter.

try (OutputStreamWriter writer = new OutputStreamWriter( new FileOutputStream("data.json"), StandardCharsets.UTF_8)) { writer.write("{\"name\": \"value\"}"); }

Closing Writers and Handling Errors

All Writer implementations should be closed after use to release system resources. The close() method flushes any buffered data and closes the underlying stream. Using try-with-resources ensures proper closing even when an exception occurs. However, note that close() can throw an IOException, and if you are handling multiple resources, you may need to manage suppression carefully. Also, flush() does not close the stream; it only forces buffered data to be written.

Choosing Between Writer and OutputStream

The decision between Writer and OutputStream depends on whether you are working with text or binary data. Use Writer for character data, especially when encoding matters. Use OutputStream for raw bytes, such as images, compressed data, or serialized objects. The table below summarizes the key differences.

AspectWriterOutputStream
Data unitCharactersBytes
Encoding handlingAutomatic via charsetNone, raw bytes
Typical useText files, logs, JSONBinary files, network
Common classesFileWriter, BufferedWriterFileOutputStream, BufferedOutputStream

When you need both, OutputStreamWriter lets you combine them, giving you the encoding control of a Writer with the flexibility of an OutputStream.

java writer: Practical Usage and Code Examples | RYUSLOG DEV