如何将Reader转换为InputStream,以及将Writer转换为OutputStream?

100

有没有简便的方法可以避免处理文本编码问题?

13个回答

96

如果你从一个字符串开始,你也可以这样做:

new ByteArrayInputStream(inputString.getBytes("UTF-8"))

10
良好的ReaderInputStream实现应该需要更少的内存--无需一次性将所有字节存储在数组中。 - Piotr Findeisen
4
我喜欢这个解决方案,因为它适用于需要对接收标准输入的代码进行单元测试的情况。 - Kedar Mhaswade

51

在处理文本编码问题时,您无法真正避免,但是Apache Commons中存在现有的解决方案:

您只需要选择所需的编码即可。


7
FYI:ReaderInputStream代码在读取字节的方式上存在一个错误(不适用于所有编码)。证据:http://illegalargumentexception.blogspot.com/2009/05/java-rough-guide-to-character-encoding.html#javaencoding_stringclass 有一个未解决的bug:https://issues.apache.org/bugzilla/show_bug.cgi?id=40455。 - McDowell
1
你可以在Apache的 commons-io 库中找到这些类:http://commons.apache.org/proper/commons-io/。 - AlikElzin-kilaka
1
@McDowell,你提到的错误是在Apache Ant的实现中,而不是commons-io的,因此与本答案无关。 - Roman

48

在Java中,Reader处理字符,InputStream处理字节。编码指定了您希望将字符表示为字节的方式,因此您不能忽略这个问题。至于避免问题,我的建议是:选择一个字符集(例如"UTF-8")并坚持使用它。

关于如何实际操作,正如已经指出的那样,"这些类的显而易见的名称是ReaderInputStreamWriterOutputStream" 令人惊讶的是,尽管Java库中包括了相反的类InputStreamReaderOutputStreamWriter,但这些类却没有被包含。

因此,许多人都提出了自己的实现,包括Apache Commons IO。根据许可问题,您可能可以在项目中包含commons-io库,甚至复制部分源代码(可在此处下载:这里)。

  • Apache WriterOutputStream: API / 源代码直链
  • 如您所见,两个类的文档都指出“JRE支持的所有字符集编码都能正确处理”。

    N.B. 这里提到了另一个答案中的评论这个漏洞。但是它影响的是Apache Ant ReaderInputStream类(在这里),而不是Apache Commons IO ReaderInputStream类。


    19

    请注意,如果您的起点是一个字符串,您可以跳过创建StringReader,使用org.apache.commons.io.IOUtils从Commons IO一次性创建一个InputStream,如下所示:

    InputStream myInputStream = IOUtils.toInputStream(reportContents, "UTF-8");
    
    当然,你仍然需要考虑文本编码,但至少转换是在一个步骤中完成的。

    5
    这种方法基本上是new ByteArrayInputStream(report.toString().getBytes("utf-8")),它需要在内存中再分配两份报告的副本。如果报告很大,那就不好了。请看我的回答。 - Oliv

    11

    使用:

    new CharSequenceInputStream(html, StandardCharsets.UTF_8);
    
    这种方法不需要将内容先转换为String,再转换为byte[],这样会在报告很大的情况下分配更多的堆内存。它会在读取流时即时地从StringBuffer中转换为字节。它使用了Apache Commons IO项目中的CharSequenceInputStream

    7

    5
    显然,这些类的名称应该是ReaderInputStream和WriterOutputStream。不幸的是,它们没有包含在Java库中。不过,谷歌是你的朋友。
    我不确定这是否能解决所有文本编码问题,因为这些问题非常棘手。
    有一个RFE,但它已关闭,不会修复。 (链接)

    1
    https://bugs.openjdk.java.net/browse/JDK-4103785 包含评论“我们有一个用于字符集编码的公共API...没有必要添加这些类”--那么在Java 7中,12年后,如何在不使用其他库的情况下实现此功能? - Piotr Findeisen

    5
    您无法避免文本编码问题,但是Apache commons-io提供以下解决方案: 请注意,这些库是Peter在koders.com中提到的库,只是链接到库而不是源代码。

    4

    您是否正在尝试将Reader的内容写入OutputStream?如果是这样,您可以更轻松地将OutputStream包装在OutputStreamWriter中,并将Reader中的char写入Writer,而不是试图将reader转换为InputStream

    final Writer writer = new BufferedWriter(new OutputStreamWriter( urlConnection.getOutputStream(), "UTF-8" ) );
    int charsRead;
    char[] cbuf = new char[1024];
    while ((charsRead = data.read(cbuf)) != -1) {
        writer.write(cbuf, 0, charsRead);
    }
    writer.flush();
    // don't forget to close the writer in a finally {} block
    

    2

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接