提问人:coconut 提问时间:11/21/2012 最后编辑:Ripon Al Wasimcoconut 更新时间:5/15/2015 访问量:11756
Java 的字符集/字符编码
Java's charsets / character encoding
问:
我有一个西班牙语文件,所以里面充满了这样的字符:
á é í ó ú ñ Ñ Á É Í Ó Ú
我必须读取文件,所以我这样做:
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;
当我阅读令牌列表时,所有的特殊字符都消失了,取而代之的是这种字符:
Ó = Ó
Ñ = Ñ
等等......
发生了什么事情?我从来没有遇到过字符集的问题(我假设是字符集问题)。是因为这台电脑吗?我能做些什么?
任何额外的建议将不胜感激,我正在学习!谢谢!
答:
您的默认编码错误。您可能需要读取 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();
}
}
}
您需要指定相关的字符编码。
BufferedReader rEntrada = new BufferedReader(
new InputStreamReader(new FileInputStream(fr), "UTF-8"));
根据我的经验,文本文件应该根据西方编码进行读取和写入:ISO-8859-1。
BufferedReader rEntrada = 新 BufferedReader( new InputStreamReader(new FileInputStream(fr), “ISO-8859-1”));
评论
其他答案为您提供了正确的方向。只是想补充一点,Guava 及其 Files.newReader(File,Charset) 帮助程序方法使创建这样的 BufferedReader 变得可读性很强(请原谅双关语):
BufferedReader rEntrada = Files.newReader(new File(ficheroEntrada), Charsets.UTF_8);
发生了什么事情?
建议使用 UTF-8 编码进行读取和写入的答案应该可以解决您的问题。我的答案更多的是关于发生了什么以及如何诊断将来的类似问题。
首先要从 http://www.utf8-chartable.de 处的 UTF-8 字符表开始。页面上有一个下拉列表,可让您浏览Unicode的不同部分。您的问题字符之一是 .检查图表显示,如果您的文件是用 UTF-8 编码的,那么字符是,UTF-8 序列是两个字节,十六进制Ó
U+00D3 LATIN CAPITAL LETTER O WITH ACUTE
c3 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 和字符集(没有借口!
评论
上一个:将方法应用于流
评论
InputStreamReader
FileReader