以UTF-8格式读取InputStream

105

我试图逐行读取一个互联网上的 text/plain 文件。我目前拥有的代码如下:

URL url = new URL("http://kuehldesign.net/test.txt");
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
LinkedList<String> lines = new LinkedList();
String readLine;

while ((readLine = in.readLine()) != null) {
    lines.add(readLine);
}

for (String line : lines) {
    out.println("> " + line);
}

文件test.txt包含¡Hélló!,我使用它来测试编码。

当我查看OutputStream(out)时,我看到它是> ¬° H√© ll√≥!。 我不认为这是OutputStream的问题,因为我可以无问题地执行out.println("é")

有没有关于如何以UTF-8读取InputStream的想法? 谢谢!


1
HTTP协议规定了编码方式。为什么不使用一个处理这个问题的库API呢?你永远不应该像这样猜测编码方式。我并不是要泼冷水:你做得很好!只是我想知道是否有更简单的方法。 - tchrist
1
很不幸,我无法访问提供text/plain文件的服务器,并且它没有使用UTF-8编码。我不知道有什么好的网络库,你有什么建议吗? - Chris Kuehl
1
看了一下文档,我觉得你根本不需要指定编码。我很惊讶他们会给你一个字节流!你确实可以访问底层的URLConnection,从中检查内容编码,然后使用正确的参数打开InputStreamReader。我快速查看了源代码,没有发现有任何能为你做这件事的东西,这似乎非常糟糕和容易出错,所以我可能错过了什么。 - tchrist
4个回答

208

问题已解决。这行代码:

BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));

需要是:

BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream(), "UTF-8"));

或者从Java 7开始:

BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream(), StandardCharsets.UTF_8));

5
我很确定构造函数的这种形式不会在输入无效时引发异常。你需要使用带有CharsetDecoder dec参数的构造函数。这是Java设计上的一个漏洞,就像OutputStreamWriter构造函数一样:只有其中的一个会告诉你什么出了问题。你必须再次使用那里的高级CharsetDecoder dec参数。唯一安全和明智的做法是将所有其他构造函数视为已弃用,因为它们不能保证可靠地运行。 - tchrist
8
自Java 7起,可以将字符集作为常量而不是字符串进行提供,例如StandardCharsets.UTF_8 - tobijdc

18
String file = "";

try {

    InputStream is = new FileInputStream(filename);
    String UTF8 = "utf8";
    int BUFFER_SIZE = 8192;

    BufferedReader br = new BufferedReader(new InputStreamReader(is,
            UTF8), BUFFER_SIZE);
    String str;
    while ((str = br.readLine()) != null) {
        file += str;
    }
} catch (Exception e) {

}

试试这个,.. :-)


9
不要使用“file += str”这种方式,应该创建一个StringBuilder并向其中添加内容。编译器可能会对字符串拼接进行优化,但很可能会产生大量垃圾。 - seand
2
如果你想将 BufferedReader 转换为字符串,请使用 Apache Commons,不要重复造轮子:String myStr = org.apache.commons.io.IOUtils.toString(myBufferedReaderInstance); - Jaime Marín
8
UTF8 = "utf8",很好的变量名;) - Nicofisi

12

每次遇到特殊字符时,我都会遇到同样的问题,它会将其标记为 ��。为了解决这个问题,我尝试使用编码:ISO-8859-1。

BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream("txtPath"),"ISO-8859-1"));

while ((line = br.readLine()) != null) {

}

我希望这篇文章能够帮助到看到它的任何人。


1
请问在UTF-8中不支持哪些字符? - USM

1
如果您使用构造函数InputStreamReader(InputStream in, Charset cs),则会自动替换坏字符。要更改此行为,请使用CharsetDecoder
public static Reader newReader(Inputstream is) {
  new InputStreamReader(is,
      StandardCharsets.UTF_8.newDecoder()
      .onMalformedInput(CodingErrorAction.REPORT)
      .onUnmappableCharacter(CodingErrorAction.REPORT)
  );
}

接着捕获java.nio.charset.CharacterCodingException异常。


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