【问题标题】:Is it overkill to use BufferedWriter and BufferedOutputStream together?一起使用 BufferedWriter 和 BufferedOutputStream 是不是有点矫枉过正?
【发布时间】:2013-03-25 19:35:09
【问题描述】:

我想写一个套接字。通过阅读有关网络 IO 的信息,在我看来,写入它的最佳方法是执行以下操作:

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

BufferedWriter 会将输入缓冲到OutputStreamWriter,这是推荐的,因为它会阻止编写器为每个字符启动编码器。

然后BufferedOutputStream 将缓冲来自Writer 的字节,以避免一次将一个字节潜在地放到网络上。

这看起来有点矫枉过正,但这一切似乎都有帮助? 感谢您的帮助..

编辑:来自OutputStreamWriter上的javadoc:

每次调用 write() 方法都会导致对给定字符调用编码转换器。结果字节在写入底层输出流之前累积在缓冲区中。可以指定此缓冲区的大小,但默认情况下它对于大多数用途来说足够大。请注意,传递给 write() 方法的字符不会被缓冲。

为了获得最高效率,请考虑将 OutputStreamWriter 包装在 BufferedWriter 中以避免频繁的转换器调用。例如:

Writer out = new BufferedWriter(new OutputStreamWriter(System.out));

【问题讨论】:

    标签: java sockets networking outputstream


    【解决方案1】:

    Buffered* 类的目的是将小型写入操作合并为一个较大的写入操作,从而减少系统调用次数并提高吞吐量。

    由于 BufferedWriter 已经在缓冲区中收集写入,然后将缓冲区中的字符转换为另一个缓冲区,并在单个操作中将该缓冲区写入底层 OutputStream,因此已通过大型写入操作调用 OutputStream。因此,BufferedOutputStream 找不到可组合的内容,简直是多余的。

    顺便说一句,BufferedWriter 也是如此:只有在一次只向写入器传递几个字符时,缓冲才会有所帮助。如果你知道调用者只写了巨大的字符串,那么 BufferedWriter 将找不到任何可以组合的东西,而且也是多余的。

    【讨论】:

    • 感谢您的回复。这说明了很多。我想我觉得省略缓冲是一种不好的形式,但你说的很有意义..
    【解决方案2】:

    BufferedWriter 会将输入缓冲到 outputStreamWriter,这是推荐的,因为它可以防止写入器为每个字符启动编码器。

    由谁推荐,在什么情况下推荐? “启动编码器”是什么意思?无论如何,您是否一次只写一个字符给作者? (我们不太了解您如何使用编写器……这可能很重要。)

    BufferedOutputStream 然后会缓冲来自 Writer 的字节,以避免一次将一个字节放入网络中。

    是什么让您认为它会一次写入一个字节?我认为OutputStreamWriter 不太可能一次向底层写入器写入一个字节,除非您真的一次写入一个字符。

    此外,我希望网络输出流使用Nagle's algorithm 之类的东西来避免发送单字节数据包。

    与优化一样,您应该根据证据进行...您是否在使用和不使用这些缓冲层的情况下进行了任何测试?

    编辑:澄清一下,我并不是说缓冲类没有用。在某些情况下,它们绝对是正确的方法。我只是说与 all 优化一样,不应盲目使用它们。您应该考虑您要优化的内容(处理器使用情况、内存使用情况、网络使用情况等)并进行测量。这里有很多因素很重要——尤其是写入模式。如果你已经在写“大块”——写大块的字符数据——那么缓冲区的影响相对较小。如果您实际上一次只写一个字符给作者,那么它们会更重要。

    【讨论】:

    • 感谢您的回复。从关于 OutputStreamWriter 的 javadoc 中,“每次调用 write() 方法都会导致对给定字符调用编码转换器。生成的字节在写入底层输出流之前累积在缓冲区中。可以指定这个缓冲区,但默认情况下它对于大多数用途来说足够大。请注意,传递给 write() 方法的字符没有缓冲。为了获得最高效率,请考虑将 OutputStreamWriter 包装在 BufferedWriter 中以避免频繁的转换器调用。” OP 编辑​​中的完整引用
    • @Bruce:考虑,当然。这与推荐不同。我会测试它。不过,如果看到它在大多数情况下会产生重大影响,我会感到非常惊讶。
    • 感谢您的有用回复。是的,我应该测试一下。这实际上是我为面试进行的编程测试的一部分,我想知道默认的正确解决方案是什么,或者至少一个没有明显错误的解决方案。
    • @Bruce Javadoc 所说的“调用”与您声称的“启动”之间存在很大差异。编码器每OutputStreamWriter启动一次。
    【解决方案3】:

    是的,这太过分了。来自Javadoc for OutputStreamWriter:“每次调用 write() 方法都会对给定字符调用编码转换器。生成的字节在写入底层输出流之前会累积在缓冲区中。”。

    【讨论】:

    • @downvoter 您在这里与 Javadoc 争论。到底哪一部分错了?
    • (我不是反对者!)我认为这是一个完美、简洁的答案!很明显,通过包装一个缓冲区,我们确保编码器仅在字符累积时触发,并且由于它有一个内部缓冲区,它只会在该缓冲区已满时触发底层写入.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-05-03
    • 2013-01-10
    • 1970-01-01
    • 2011-10-24
    • 2012-07-06
    • 1970-01-01
    • 2015-03-09
    相关资源
    最近更新 更多