Java 的字符集/字符编码

Java's charsets / character encoding

提问人:coconut 提问时间:11/21/2012 最后编辑:Ripon Al Wasimcoconut 更新时间:5/15/2015 访问量:11756

问:

我有一个西班牙语文件,所以里面充满了这样的字符:

 á é í ó ú ñ Ñ Á É Í Ó Ú 

我必须读取文件,所以我这样做:

fr = new FileReader(ficheroEntrada);
BufferedReader rEntrada = new BufferedReader(fr);

String linea = rEntrada.readLine();
if (linea == null) {
logger.error("ERROR: Empty file.");
return null;
} 
String delimitador = "[;]";
String[] tokens = null;

List<String> token = new ArrayList<String>();
while ((linea = rEntrada.readLine()) != null) {
    // Some parsing specific to my file. 
    tokens = linea.split(delimitador);
    token.add(tokens[0]);
    token.add(tokens[1]);
}
logger.info("List of tokens: " + token);
return token;

当我阅读令牌列表时,所有的特殊字符都消失了,取而代之的是这种字符:

Ó = Ó
Ñ = Ñ

等等......

发生了什么事情?我从来没有遇到过字符集的问题(我假设是字符集问题)。是因为这台电脑吗?我能做些什么?

任何额外的建议将不胜感激,我正在学习!谢谢!

Java 编码 非 ASCII 字符

评论

1赞 nhahtdh 11/21/2012
使用并指定适当的编码。 将采用“默认”编码,因此它不会正确解码字符。InputStreamReaderFileReader

答:

2赞 Rob Audenaerde 11/21/2012 #1

您的默认编码错误。您可能需要读取 UTF8 或 latin1。请参阅此代码片段,了解如何在流上设置编码。另请参阅 Java,默认编码

public class Program {

    public static void main(String... args)  {

        if (args.length != 2) {
            return ;
        }

        try {
            Reader reader = new InputStreamReader(
                        new FileInputStream(args[0]),"UTF-8");
            BufferedReader fin = new BufferedReader(reader);
            Writer writer = new OutputStreamWriter(
                       new FileOutputStream(args[1]), "UTF-8");
            BufferedWriter fout = new BufferedWriter(writer);
            String s;
            while ((s=fin.readLine())!=null) {
                fout.write(s);
                fout.newLine();
            }

            //Remember to call close. 
            //calling close on a BufferedReader/BufferedWriter 
            // will automatically call close on its underlying stream 
            fin.close();
            fout.close();

        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}
5赞 kosa 11/21/2012 #2

您需要指定相关的字符编码。

BufferedReader rEntrada  = new BufferedReader(
    new InputStreamReader(new FileInputStream(fr), "UTF-8"));
2赞 Thinhbk 11/21/2012 #3

根据我的经验,文本文件应该根据西方编码进行读取和写入:ISO-8859-1。

BufferedReader rEntrada = 新 BufferedReader( new InputStreamReader(new FileInputStream(fr), “ISO-8859-1”));

评论

1赞 danigonlinea 4/5/2014
我的文档上有 áéíóú 字符,这种编码对我有用。UTF-8 没有。谢谢。
0赞 ShyJ 11/21/2012 #4

其他答案为您提供了正确的方向。只是想补充一点,Guava 及其 Files.newReader(File,Charset) 帮助程序方法使创建这样的 BufferedReader 变得可读性很强(请原谅双关语):

BufferedReader rEntrada = Files.newReader(new File(ficheroEntrada), Charsets.UTF_8);
5赞 Guido Simone 11/21/2012 #5

发生了什么事情?

建议使用 UTF-8 编码进行读取和写入的答案应该可以解决您的问题。我的答案更多的是关于发生了什么以及如何诊断将来的类似问题。

首先要从 http://www.utf8-chartable.de 处的 UTF-8 字符表开始。页面上有一个下拉列表,可让您浏览Unicode的不同部分。您的问题字符之一是 .检查图表显示,如果您的文件是用 UTF-8 编码的,那么字符是,UTF-8 序列是两个字节,十六进制ÓU+00D3 LATIN CAPITAL LETTER O WITH ACUTEc3 93

现在让我们检查一下 http://en.wikipedia.org/wiki/ISO/IEC_8859-1 处的 ISO-8859-1 字符集,因为这也是一个流行的字符集。但是,这是单字节字符集之一。每个有效字符都由一个字节表示,这与 UTF-8 不同,UTF-8 的字符可以用 1、2 或 3 个字节表示。

请注意,C3 处的字符看起来像 Ã,但 93 处没有字符。因此,您的默认编码可能不是 ISO-8859-1。

接下来,让我们在 http://en.wikipedia.org/wiki/Windows-1252 检查 Windows 1252。这与 ISO-8859-1 几乎相同,但用有用的字符填充了一些空白。在那里,我们有一场比赛。Windows 1252 中的序列 C3 93 正是字符串Ó

所有这些都告诉我,您的文件是 UTF-8 编码的,但是您的 Java 环境配置了 Windows 1252 作为默认编码。如果修改代码以显式指定字符集 (“UTF-8”) 而不是使用默认值,则代码在不同环境中失败的可能性较小。

但请记住 - 这很容易以另一种方式发生。如果您的文件主要是西班牙语文本,那么它很可能是 ISO-8859-1 或 Windows 1252 编码文件。在这种情况下,在计算机上运行的代码可以正常工作,将其切换为读取“UTF-8”编码将创建一组不同的乱码。

这是您获得相互矛盾的建议的部分原因。不同的人根据他们的平台遇到了不同的不匹配,因此发现了不同的修复方法。

如有疑问,我会在 emacs 中读取文件并切换到十六进制模式,这样我就可以在文件中看到确切的二进制数据。我相信有更好、更现代的方法可以做到这一点。

最后一个想法 - 可能值得一读 绝对最低限度 每个软件开发人员绝对、积极地必须了解 Unicode 和字符集(没有借口!

评论

0赞 kosa 11/22/2012
+1.关于背景的好信息。我建议标记为 Wiki。