inputStream和utf 8有时会显示"?"人物

时间:2015-03-10 17:10:49

标签: java utf-8

所以我已经处理了这个问题已经有一个多月了,而且我还在谷歌内外搜索了几乎所有可能的相关解决方案,但是我找不到任何真正解决我问题的方法。 我的问题是我试图从网站上下载一个html源代码,但我在大多数情况下得到的是一些文字显示了一些"?"其中的人物,很可能是因为该网站是希伯来语。 这是我的代码,

    public static InputStream openHttpGetConnection(String url)
            throws Exception {
        InputStream inputStream = null;
        HttpClient httpClient = new DefaultHttpClient();
        HttpResponse httpResponse = httpClient.execute(new HttpGet(url));
        inputStream = httpResponse.getEntity().getContent();
        return inputStream;

    }
    public static String downloadSource(String url) {
        int BUFFER_SIZE = 1024;

        InputStream inputStream = null;
        try {
            inputStream = openHttpGetConnection(url);
        } catch (Exception e) {
            // TODO: handle exception
        }
        int bytesRead;
        String str = "";
        byte[] inpputBuffer = new byte[BUFFER_SIZE];
        try {
            while ((bytesRead = inputStream.read(inpputBuffer)) > 0) {
                String read = new String(inpputBuffer, 0, bytesRead,"UTF-8");
                str +=read;

            }
        } catch (Exception e) {
            // TODO: handle exception
        }
        return str;

    }

感谢。

2 个答案:

答案 0 :(得分:1)

要使用给定的编码从字节流中读取字符,请使用Reader。在你的情况下,它将是这样的:

    InputStreamReader isr = new InputStreamReader(inpputStream, "UTF-8");
    char[] inputBuffer = new char[BUFFER_SIZE];

    while ((charsRead = isr.read(inputBuffer, 0, BUFFER_SIZE)) > 0) {
        String read = new String(inputBuffer, 0, charsRead);
        str += read;
    }

您可以看到字节将直接作为字符读取 - 读者的问题是知道它是否需要读取一个或两个字节,例如,创建字符缓冲区。它基本上是你的方法,但解码时正在读入字节,而不是之后。

答案 1 :(得分:0)

InputStream转换为字符串需要指定编码,就像在new String(inpputBuffer, 0, bytesRead,"UTF-8");处一样。

但你的方法有几个缺点。

你怎么知道你必须使用UTF8?

在检索HTTP内容时,一般来说,您无法事先知道HTTP响应中将使用哪种编码。但HTTP提供了一种使用Content-Type标头指定的机制。

更具体地说,您的响应对象应该有一个Content-Type“标题”,其中包含一个名为encoding的“属性”。在回复中,它应该类似于:

Content-Type: text/html; encoding=UTF-8

您应该使用encoding=部分之后的内容将byte转换为char。 看到您似乎使用Apache HTTPClient,他们的文档说明:

  

您可以在每个方法中使用addRequestHeader方法为请求设置内容类型标头,并使用getResponseCharSet方法检索响应正文的编码。
  如果已知响应是String,则可以使用getResponseBodyAsString方法,如果未指定charset,则该方法将自动使用Content-Type标头或ISO-8859-1中指定的编码。

替代方式

如果没有Content-Type标头,并且知道您的内容是HTML,那么您可以尝试使用某种编码(最好是UTF或ISO Latin)将其转换为字符串,并且尝试找到一些匹配<meta charset="UTF-8">的内容,并将其用作charset。这应该只是故障转移。

任何字节序列都不能转换为String

第二个缺点是您从流中读取任意数量的字节,并尝试将其转换为字符串,这可能是不可能的。

实际上,UTF-8可以跨多个字节编码一些“字符”。例如,“é”可以编码为0xC3A9。例如,假设响应包含两个“é”字符。如果您第一次拨打read,则会返回:

[c3, a9, c3]

使用新String(byte[], off, enc)转换为字符串会使最后一个字节分开,因为它与有效的UTF8序列不匹配。

您的以下阅读将获得剩下的内容

[a9]

哪个(不管是什么)不是“é”字符。

底线:您无法使用模式将有效的UTF-8序列转换为字节。

前进:您使用HTTPClient,使用他们的HTTP响应方法转换为String。 如果您希望自己动手,最简单的方法是将输入复制到字节数组,然后转换字节数组。类似于(伪代码)的东西:

ByteArrayOutputStream responseContent = new ByteArrayOutputStream()
copyAllBytes(responseInputStream, responseContent)
byte[] rawResponse = responseContent.toByteArray();
String stringResponse = new String(rawResponse, encoding);

但如果你想要一个完全流式的实现(一个不会将响应完全缓冲到内存中),或者作为@jas的答案,你可以使用CharsetDecoder,将inputStream包装到一个阅读器并连接输出(最好是StringBuilder,如果要发生大量连接,它应该更快)。