所以我已经处理了这个问题已经有一个多月了,而且我还在谷歌内外搜索了几乎所有可能的相关解决方案,但是我找不到任何真正解决我问题的方法。 我的问题是我试图从网站上下载一个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;
}
感谢。
答案 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");
处一样。
但你的方法有几个缺点。
在检索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。这应该只是故障转移。
第二个缺点是您从流中读取任意数量的字节,并尝试将其转换为字符串,这可能是不可能的。
实际上,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,如果要发生大量连接,它应该更快)。