如何将Reader转换为InputStream而将Writer转换为OutputStream?


Answers:


45

您确实无法避免处理文本编码问题,但是Apache Commons中已有一些解决方案:

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


7
仅供参考:ReaderInputStream代码在读取字节的方式上有一个错误(不适用于所有编码)。证明:legalargumentexception.blogspot.com/2009/05/…有一个公开的错误:issues.apache.org/bugzilla/show_bug.cgi?id = 40455
McDowell,2009年

1
您可以在Apache的commons-io库中找到这些类:commons.apache.org/proper/commons-io
AlikElzin-kilaka 2014年

@McDowell,您提到的错误是在Apache Ant的实现中,而不是commons-io的实现中,因此与该答案无关。
罗马

94

如果从字符串开始,还可以执行以下操作:

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

7
良好的ReaderInputStream实现将需要较少的内存-无需一次将所有字节存储在数组中。
Piotr Findeisen

3
我喜欢这种解决方案,因为它适用于需要对接受(例如)标准输入中的输入的代码进行单元测试的情况。
Kedar Mhaswade

42

好吧,阅读器处理字符,而InputStream处理字节。编码指定了您希望如何以字节表示字符,因此您不能真正忽略该问题。至于避免问题,我的看法是:选择一个字符集(例如“ UTF-8”)并坚持下去。

关于如何实际执行,正如已经指出的那样,“ 这些类的明显名称是ReaderInputStreamWriterOutputStream ”令人惊讶的是,即使“相反”类InputStreamReaderOutputStreamWriter “相反”的类,它们也不包含在Java库中。包括在内。

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

如您所见,这两个类的文档都指出“正确处理了JRE支持的所有字符集编码”。

注意:这里对其他答案之一的评论提到了此错误。但这会影响Apache Ant ReaderInputStream类(此处),而不影响 Apache Commons IO ReaderInputStream类。


19

还要注意,如果您以String开头,则可以使用Commons IO的 org.apache.commons.io.IOUtils跳过创建StringReader并一步一步创建InputStream的方法,如下所示:

InputStream myInputStream = IOUtils.toInputStream(reportContents, "UTF-8");

当然,您仍然需要考虑文本编码,但是至少转换是一步完成的。


4
此方法基本上new ByteArrayInputStream(report.toString().getBytes("utf-8"))可以做到,这涉及在内存中分配报告的两个附加副本。如果报告很大,那就不好。看我的答案。
奥利夫,2014年

8

用:

new CharSequenceInputStream(html, StandardCharsets.UTF_8);

这种方式不需要先转换为String,然后再转换为byte[],在报表较大的情况下会分配更多的堆内存。直接从StringBuffer读取流时,它将即时转换为字节。

它使用来自Apache Commons IO项目的CharSequenceInputStream



5

这些类的明显名称是ReaderInputStream和WriterOutputStream。不幸的是,这些未包含在Java库中。但是,谷歌是你的朋友。

我不确定它能否解决所有噩梦般的文本编码问题。

有一个RFE,但已关闭,无法解决。


1
bugs.openjdk.java.net/browse/JDK-4103785包含注释“我们有一个用于字符集编码的公共API ...没有令人信服的理由添加这些类” –因此,在Java 7中如何做到这一点而无需额外的操作图书馆,走了十二年?
Piotr Findeisen


4

你们是不是写的内容ReaderOutputStream?如果是这样,您将有一个更轻松的时间将包裹OutputStreamOutputStreamWriter并将chars从写入ReaderWriter,而不是尝试将阅读器转换为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

1

使用WriterOutputStream时的警告-它并不总是能正确地/与常规输出流相同地将二进制数据写入文件。我有一个问题,这使我花了一段时间才找到答案。

如果可以,我建议您使用输出流作为基础,如果需要编写字符串,请在流周围使用OUtputStreamWriter包装器来完成此操作。将文本转换为字节要比其他方法可靠得多,这很可能是WriterOutputStream不属于标准Java库的一部分的原因。



-1

用于仅使用java提供的内容读取流中的字符串。

InputStream s = new BufferedInputStream( new ReaderInputStream( new StringReader("a string")));

6
ReaderInputStream在Apache Commons IO中。
Will Beason 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.