1. 使用原生 Java 实现

在没有第三方库的情况下,我们可以用 JDK 自带的类完成 ReaderInputStream 的转换。核心思路是:先通过 Reader 读取字符数据到内存,再将字符串按指定编码转为字节数组,最后包装成 ByteArrayInputStream

✅ 优点:不依赖外部库
❌ 缺点:代码略长,需要手动管理缓冲区

示例代码如下:

@Test
public void givenUsingPlainJava_whenConvertingReaderIntoInputStream_thenCorrect() 
  throws IOException {
    Reader initialReader = new StringReader("With Java");

    char[] charBuffer = new char[8 * 1024];
    StringBuilder builder = new StringBuilder();
    int numCharsRead;
    while ((numCharsRead = initialReader.read(charBuffer, 0, charBuffer.length)) != -1) {
        builder.append(charBuffer, 0, numCharsRead);
    }
    InputStream targetStream = new ByteArrayInputStream(
      builder.toString().getBytes(StandardCharsets.UTF_8));

    initialReader.close();
    targetStream.close();
}

⚠️ 注意:

  • 使用了 8KB 的字符缓冲区,避免频繁 I/O 操作
  • 显式指定 UTF-8 编码,防止因 JVM 默认编码不同导致乱码(踩坑点!)
  • 手动调用 close() 释放资源,Java 7+ 推荐使用 try-with-resources 更安全

2. 使用 Guava 实现

如果你的项目中已经引入了 Guava,那转换可以变得非常简单粗暴。

Guava 提供了 CharStreams.toString() 方法,能一键把 Reader 的内容读取为字符串,后续操作就和上面类似了。

✅ 优点:代码简洁,API 友好
❌ 缺点:需引入 Guava,对轻量级项目可能略重

@Test
public void givenUsingGuava_whenConvertingReaderIntoInputStream_thenCorrect() 
  throws IOException {
    Reader initialReader = new StringReader("With Guava");

    InputStream targetStream = 
      new ByteArrayInputStream(CharStreams.toString(initialReader)
      .getBytes(Charsets.UTF_8));

    initialReader.close();
    targetStream.close();
}

📌 小贴士:Charsets.UTF_8 是 Guava 提供的常量,等价于 StandardCharsets.UTF_8,但更早支持。

3. 使用 Apache Commons IO 实现

Apache Commons IO 是 Java 开发中非常常用的工具库,提供了多种便捷的 I/O 操作封装。

3.1 使用 ReaderInputStream

这是最直接的方式——ReaderInputStream 构造器直接接受 ReaderCharset,内部自动处理字符到字节的转换。

@Test
public void givenUsingCommonsIOReaderInputStream_whenConvertingReaderIntoInputStream() 
  throws IOException {
    Reader initialReader = new StringReader("With Commons IO");

    InputStream targetStream = new ReaderInputStream(initialReader, Charsets.UTF_8);

    initialReader.close();
    targetStream.close();
}

⚠️ 注意:ReaderInputStream 是边读边转,不会一次性加载全部内容到内存,适合大文件场景。

3.2 使用 IOUtils

也可以通过 IOUtils.toString() 先转成字符串,再用 toInputStream() 转回字节流。

@Test
public void givenUsingCommonsIOUtils_whenConvertingReaderIntoInputStream() 
  throws IOException {
    Reader initialReader = new StringReader("With Commons IO");

    InputStream targetStream = 
      IOUtils.toInputStream(IOUtils.toString(initialReader), Charsets.UTF_8);

    initialReader.close();
    targetStream.close();
}

⚠️ 缺点:IOUtils.toString(reader) 会将整个内容加载进内存,不适合处理大文本,容易 OOM。

📌 推荐使用场景:

  • 小数据量:两种方式都可
  • 大数据量或流式处理:✅ 优先选 ReaderInputStream

4. 总结

方式 是否推荐 适用场景
原生 Java ⚠️ 一般 无第三方依赖,需手动控制缓冲
Guava ✅ 推荐 已引入 Guava,代码简洁
Commons IO - ReaderInputStream ✅ 强烈推荐 流式处理、大文件、生产环境首选
Commons IO - IOUtils ⚠️ 谨慎 仅限小文本,避免内存溢出

📌 核心建议:

  • ✅ 始终显式指定字符编码(如 UTF-8),不要依赖默认编码
  • ✅ 优先使用 try-with-resources 管理资源,避免泄露
  • ✅ 大文本处理务必选择流式方案(如 ReaderInputStream

完整示例代码已上传至 GitHub:https://github.com/baeldung/java-tutorials/tree/master/core-java-modules/core-java-io-conversions


原始标题:Java - Reader to InputStream