Java的字符集/字符编码

3

我有一个用西班牙语写的文件,所以它充满了像这样的字符:

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

我需要读取文件,因此我这样做:
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;

当我阅读令牌列表时,所有的特殊字符都消失了,并被这种字符所代替:

Ó = Ó
Ñ = Ñ

等等,发生了什么?我以前从没遇到过字符集的问题(我认为这是一个字符集问题)。是因为这台电脑吗?我该怎么办?

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


1
使用InputStreamReader并指定适当的编码方式。FileReader会假设“默认”编码,因此无法正确解码字符。 - nhahtdh
5个回答

5

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

BufferedReader rEntrada  = new BufferedReader(
    new InputStreamReader(new FileInputStream(fr), "UTF-8"));

5
“发生了什么?”建议阅读和编写UTF-8编码来解决你的问题。我的回答更多关于发生了什么以及如何诊断类似的问题。首先要开始的地方是UTF-8字符表http://www.utf8-chartable.de。页面上有一个下拉菜单,可以浏览Unicode的不同部分。你的问题字符之一是Ó。检查图表揭示,如果你的文件被编码为UTF-8,则字符是U+00D3 LATIN CAPITAL LETTER O WITH ACUTE,UTF-8序列是两个字节,十六进制为c3 93
现在让我们查看ISO-8859-1字符集,链接为http://en.wikipedia.org/wiki/ISO/IEC_8859-1,因为这也是一种流行的字符集。但是,这是其中一种单字节字符集。每个有效字符由一个字节表示,不像UTF-8,其中一个字符可以由1、2或3个字节表示。
请注意,C3处的字符看起来像Ã,但93处没有字符。因此,您的默认编码可能不是ISO-8859-1。
接下来让我们查看Windows 1252,链接为http://en.wikipedia.org/wiki/Windows-1252。它几乎与ISO-8859-1相同,但用有用的字符填充了一些空白空间。然后我们找到了匹配项。在Windows 1252中,序列C3 93正是字符字符串Ó
所有这些告诉我,你的文件是UTF-8编码,但你的Java环境配置为Windows 1252作为默认编码。如果你修改你的代码,显式指定字符集(“UTF-8”)而不是使用默认值,你的代码在不同环境下失败的可能性将会降低。
请记住 - 这也可能发生在另一种情况下。如果你有一个主要包含西班牙文本的文件,它也可能是ISO-8859-1或Windows 1252编码的文件。在这种情况下,你在你的机器上运行的代码将正常工作,并将其切换到读取“UTF-8”编码将创建一组不同的乱码字符。
这是你得到矛盾建议的部分原因。不同的人基于他们的平台遇到了不同的不匹配,因此发现了不同的解决方法。
当你不确定时,我会在emacs中读取文件并切换到hexl模式,以便我可以看到文件中精确的二进制数据。我相信有更好、更现代的方法来做到这一点。
最后一个想法 - 值得阅读关于Unicode和字符集每个软件开发人员绝对必须知道的绝对最低限度(没有借口!)

+1。背景信息很好。我建议将其标记为维基。 - kosa

2

您的默认编码有误。您可能需要阅读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();
        }

    }
}

2

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

BufferedReader rEntrada = new BufferedReader( new InputStreamReader(new FileInputStream(fr), "ISO-8859-1"));


1
我在我的文档中有áéíóú字符,这些编码对我有效。UTF-8则无效。谢谢。 - danigonlinea

0

其他答案给了你正确的方向。只是想补充一下Guava ,使用其Files.newReader(File,Charset)帮助方法可以使创建BufferedReader变得更加易读(请原谅双关语):

BufferedReader rEntrada = Files.newReader(new File(ficheroEntrada), Charsets.UTF_8);

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