Is it overkill to use BufferedWriter and BufferedOutputStream together?
Asked Answered
S

3

12

I want to write to a socket. From reading about network IO, it seems to me that the optimal way to write to it is to do something like this:

OutputStream outs=null;
BufferedWriter out=null;
out =
  new BufferedWriter(
    new OutputStreamWriter(new BufferedOutputStream(outs),"UTF-8"));

The BufferedWriter would buffer the input to the OutputStreamWriter which is recommended, because it prevents the writer from starting up the encoder for each character.

The BufferedOutputStream would then buffer the bytes from the Writer to avoid putting one byte at a time potentially onto the network.

It looks a bit like overkill, but it all seems like it helps? Grateful for any help..

EDIT: From the javadoc on OutputStreamWriter:

Each invocation of a write() method causes the encoding converter to be invoked on the given character(s). The resulting bytes are accumulated in a buffer before being written to the underlying output stream. The size of this buffer may be specified, but by default it is large enough for most purposes. Note that the characters passed to the write() methods are not buffered.

For top efficiency, consider wrapping an OutputStreamWriter within a BufferedWriter so as to avoid frequent converter invocations. For example:

Writer out = new BufferedWriter(new OutputStreamWriter(System.out));
Spineless answered 3/4, 2013 at 22:12 Comment(0)
L
2

The BufferedWriter would buffer the input to the outputStreamWriter, which is recommended because it prevents the writer from starting up the encoder for each character.

Recommended by who, and in what context? What do you mean by "starting up the encoder"? Are you writing a single character at a time to the writer anyway? (We don't know much about how you're using the writer... that could be important.)

The BufferedOutputStream would then buffer the bytes from the Writer to avoid putting one byte at a time potentially onto the network.

What makes you think it would write one byte at a time? I think it very unlikely that OutputStreamWriter will write a byte at a time to the underlying writer, unless you really write a character at a time to it.

Additionally, I'd expect the network output stream to use something like Nagle's algorithm to avoid sending single-byte packets.

As ever with optimization, you should do it based on evidence... have you done any testing with and without these layers of buffering?

EDIT: Just to clarify, I'm not saying the buffering classes are useless. In some cases they're absolutely the right way to go. I'm just saying that as with all optimization, they shouldn't be used blindly. You should consider what you're trying to optimize for (processor usage, memory usage, network usage etc) and measure. There are many factors which matter here - not least of which is the write pattern. If you're already writing "chunkily" - writing large blocks of character data - then the buffers will have relatively little impact. If you're actually writing a single character at a time to the writer, then they would be more significant.

Longhorn answered 3/4, 2013 at 22:17 Comment(4)
Thanks for your reply. From the javadoc on OutputStreamWriter, "Each invocation of a write() method causes the encoding converter to be invoked on the given character(s). The resulting bytes are accumulated in a buffer before being written to the underlying output stream. The size of this buffer may be specified, but by default it is large enough for most purposes. Note that the characters passed to the write() methods are not buffered. For top efficiency, consider wrapping an OutputStreamWriter within a BufferedWriter so as to avoid frequent converter invocations." Whole quote in OP editSpineless
@Bruce: Consider, sure. That's not the same as recommending. I would test it. I would be very surprised to see it make a significant difference in most cases though.Longhorn
Thanks for your useful replies. Yes, I should test it. It's actually as part of a programming test I did for an interview, and I wanted to know what the sort of default correct solution would be, or at least one not obviously wrong.Spineless
@Spineless There's a large difference between 'invoking', which is what the Javadoc says, and 'starting up', which is what you claimed. The encoder is started once per OutputStreamWriter.Centroid
O
11

The purpose of the Buffered* classes is to coalesce small write operations into a larger one, thereby reducing the number of system calls, and increasing throughput.

Since a BufferedWriter already collects writes in a buffer, then converts the characters in the buffer into another buffer, and writes that buffer to the underlying OutputStream in a single operation, the OutputStream is already invoked with large write operations. Therefore, a BufferedOutputStream finds nothing to combine, and is simply redundant.

As an aside, the same can apply to the BufferedWriter: buffering will only help if the writer is only passed few characters at a time. If you know the caller only writes huge strings, the BufferedWriter will find nothing to combine and is redundant, too.

Oberon answered 3/4, 2013 at 22:36 Comment(1)
Thanks for your reply. That clarifies a lot. I think I felt like it was bad form to leave out buffering, but what you say makes a lot of sense..Spineless
L
2

The BufferedWriter would buffer the input to the outputStreamWriter, which is recommended because it prevents the writer from starting up the encoder for each character.

Recommended by who, and in what context? What do you mean by "starting up the encoder"? Are you writing a single character at a time to the writer anyway? (We don't know much about how you're using the writer... that could be important.)

The BufferedOutputStream would then buffer the bytes from the Writer to avoid putting one byte at a time potentially onto the network.

What makes you think it would write one byte at a time? I think it very unlikely that OutputStreamWriter will write a byte at a time to the underlying writer, unless you really write a character at a time to it.

Additionally, I'd expect the network output stream to use something like Nagle's algorithm to avoid sending single-byte packets.

As ever with optimization, you should do it based on evidence... have you done any testing with and without these layers of buffering?

EDIT: Just to clarify, I'm not saying the buffering classes are useless. In some cases they're absolutely the right way to go. I'm just saying that as with all optimization, they shouldn't be used blindly. You should consider what you're trying to optimize for (processor usage, memory usage, network usage etc) and measure. There are many factors which matter here - not least of which is the write pattern. If you're already writing "chunkily" - writing large blocks of character data - then the buffers will have relatively little impact. If you're actually writing a single character at a time to the writer, then they would be more significant.

Longhorn answered 3/4, 2013 at 22:17 Comment(4)
Thanks for your reply. From the javadoc on OutputStreamWriter, "Each invocation of a write() method causes the encoding converter to be invoked on the given character(s). The resulting bytes are accumulated in a buffer before being written to the underlying output stream. The size of this buffer may be specified, but by default it is large enough for most purposes. Note that the characters passed to the write() methods are not buffered. For top efficiency, consider wrapping an OutputStreamWriter within a BufferedWriter so as to avoid frequent converter invocations." Whole quote in OP editSpineless
@Bruce: Consider, sure. That's not the same as recommending. I would test it. I would be very surprised to see it make a significant difference in most cases though.Longhorn
Thanks for your useful replies. Yes, I should test it. It's actually as part of a programming test I did for an interview, and I wanted to know what the sort of default correct solution would be, or at least one not obviously wrong.Spineless
@Spineless There's a large difference between 'invoking', which is what the Javadoc says, and 'starting up', which is what you claimed. The encoder is started once per OutputStreamWriter.Centroid
C
2

Yes it is overkill. From the Javadoc for OutputStreamWriter: "Each invocation of a write() method causes the encoding converter to be invoked on the given character(s). The resulting bytes are accumulated in a buffer before being written to the underlying output stream.".

Centroid answered 4/4, 2013 at 2:38 Comment(1)
(I'm not the downvoter!) I think this is a perfect, succinct answer! It's clear that by wrapping with a Buffer, we ensure that the encoder is only triggered when there's an accumulation of chars, and as it has an internal buffer, it will only trigger underlying writes when that buffer is full.Vicinage

© 2022 - 2024 — McMap. All rights reserved.