1. 使用原生 Java 实现

在不引入第三方库的情况下,直接用 JDK 自带的 API 将 Reader 转成 String 是基础功。这里有两个常见写法:逐字符读取和批量读取。

方式一:逐字符读取(适用于小数据量)

简单粗暴,但性能较差,尤其是数据量大时,字符串频繁拼接会触发多次对象创建,不推荐用于生产环境

@Test
public void givenUsingPlainJava_whenConvertingReaderIntoStringV1_thenCorrect() 
    throws IOException {
    StringReader reader = new StringReader("Hello, Baeldung!");
    int intValueOfChar;
    String targetString = "";
    while ((intValueOfChar = reader.read()) != -1) {
        targetString += (char) intValueOfChar;
    }
    reader.close();
    assertEquals("Hello, Baeldung!", targetString);
}

⚠️ 踩坑提醒:String += char 在循环中会产生大量临时对象,GC 压力大。


方式二:批量读取 + StringBuilder(推荐)

使用固定大小的字符数组批量读取,配合 StringBuilder 避免重复创建字符串对象,性能更好,适合处理大文本

@Test
public void givenUsingPlainJava_whenConvertingReaderIntoStringV2_thenCorrect() 
    throws IOException {
    Reader initialReader = new StringReader("This is a longer text for testing.");
    char[] arr = new char[8 * 1024];  // 8KB 缓冲区
    StringBuilder buffer = new StringBuilder();
    int numCharsRead;
    while ((numCharsRead = initialReader.read(arr, 0, arr.length)) != -1) {
        buffer.append(arr, 0, numCharsRead);
    }
    initialReader.close();
    String targetString = buffer.toString();
    assertEquals("This is a longer text for testing.", targetString);
}

📌 核心要点:

  • 缓冲区大小建议设为 8KB(常见 I/O 块大小)
  • 使用 StringBuilder 而非 StringBuffer(单线程无需同步开销)

2. 使用 Guava

Google Guava 提供了非常简洁的工具类 CharStreams,一行代码搞定转换,代码可读性强,推荐在使用 Guava 的项目中采用

@Test
public void givenUsingGuava_whenConvertingReaderIntoString_thenCorrect() 
    throws IOException {
    Reader initialReader = CharSource.wrap("With Google Guava").openStream();
    String targetString = CharStreams.toString(initialReader);
    initialReader.close();
    assertEquals("With Google Guava", targetString);
}

✅ 优点:

  • API 简洁,语义清晰
  • 内部已做性能优化(使用缓冲)

❌ 注意:

  • 需要引入 com.google.guava:guava 依赖
  • CharSource.wrap().openStream() 返回的是 Reader,别忘了关闭资源(或用 try-with-resources)

📌 建议用 try-with-resources 更安全:

try (Reader reader = CharSource.wrap("With Google Guava").openStream()) {
    String result = CharStreams.toString(reader);
}

3. 使用 Apache Commons IO

Apache Commons IO 是 Java 项目中最常用的 I/O 工具库之一,IOUtils.toString() 方法广为人知,简单直接,生态支持好

@Test
public void givenUsingCommonsIO_whenConvertingReaderIntoString_thenCorrect() 
    throws IOException {
    Reader initialReader = new StringReader("With Apache Commons IO");
    String targetString = IOUtils.toString(initialReader);
    initialReader.close();
    assertEquals("With Apache Commons IO", targetString);
}

✅ 优点:

  • 方法名直观,易于理解
  • 社区广泛,几乎成为事实标准
  • 支持重载方法指定字符编码(如 IOUtils.toString(Reader, Charset)

❌ 注意:

  • 自 2.6 版本起,IOUtils 中部分方法已标记为过期,推荐使用 IOUtils.toString(Reader) 或迁移到 commons-io-2.11+ 的新 API
  • 同样需要注意资源关闭

📌 推荐写法(自动资源管理):

try (Reader reader = new StringReader("With Apache Commons IO")) {
    String result = IOUtils.toString(reader);
}

总结对比

方式 是否需要依赖 性能 可读性 推荐场景
原生 Java(逐字符) ❌ ⭐☆☆ ⭐☆☆ 仅学习用途
原生 Java(批量) ✅ ⭐⭐⭐ ⭐⭐☆ 无依赖项目,需控制体积
Guava ✅ ⭐⭐⭐ ⭐⭐⭐ 已使用 Guava 的项目
Commons IO ✅ ⭐⭐⭐ ⭐⭐⭐ 主流选择,兼容性好

📌 最终建议

  • 如果项目已经引入 GuavaCommons IO,优先使用对应工具方法
  • 否则,使用原生 Java 的批量读取方案,避免性能陷阱
  • ⚠️ 所有 Reader 操作务必注意资源释放,推荐统一使用 try-with-resources

原始标题:Java - Reader to String | Baeldung