依赖于默认编码,我应该使用什么以及为什么?

时间:2014-03-01 13:51:15

标签: java encoding internationalization findbugs

FindBugs报告了一个错误:

  

依赖于默认编码   发现对将执行字节到String(或String到byte)转换的方法的调用,并假设默认平台编码是合适的。这将导致应用程序行为在平台之间变化。使用备用API并明确指定charset名称或Charset对象。

我像这样使用FileReader(只是一段代码):

public ArrayList<String> getValuesFromFile(File file){
    String line;
    StringTokenizer token;
    ArrayList<String> list = null;
    BufferedReader br = null;
    try {
        br = new BufferedReader(new FileReader(file));
        list = new ArrayList<String>();
        while ((line = br.readLine())!=null){
            token = new StringTokenizer(line);
            token.nextToken();
            list.add(token.nextToken());
    ...

纠正我需要更改的错误

br = new BufferedReader(new FileReader(file));

br = new BufferedReader(new InputStreamReader(new FileInputStream(file), Charset.defaultCharset()));

当我使用PrintWriter时,发生了同样的错误。所以现在我有一个问题。当我可以(应该)使用FileReader和PrintWriter时,如果不是很好的做法依赖于默认编码? 第二个问题是正确使用Charset.defaultCharset()?我决定使用这种方法自动定义用户操作系统的字符集。

4 个答案:

答案 0 :(得分:22)

如果文件在您的应用程序的控制之下,并且您希望以平台的默认编码对文件进行编码,则可以使用默认的平台编码。明确地指定它会使您和未来的维护者更清楚,这是您的意图。例如,对于文本编辑器来说,这将是一个合理的默认设置,然后编写该平台上任何其他编辑器可以读取的文件。

另一方面,如果要确保可以在文件中写入任何可能的字符,则应使用UTF8等通用编码。

如果文件来自外部应用程序,或者应该与外部应用程序兼容,那么您应该使用此外部应用程序所期望的编码。

你必须意识到的是,如果你像在机器上一样写一个文件,并且在另一台没有相同默认编码的机器上进行读取,你就不一定能够阅读你所写的内容。使用特定的编码,写入和读取,如UTF8,确保文件将始终相同,无论在编写文件时使用何种平台。

答案 1 :(得分:20)

理想情况下,它应该是:

try (InputStream in = new FileInputStream(file);
     Reader reader = new InputStreamReader(in, StandardCharsets.UTF_8);
     BufferedReader br = new BufferedReader(reader)) {

...或:

try (BufferedReader br = Files.newBufferedReader(path, StandardCharsets.UTF_8)) {

...假设文件编码为UTF-8。

对于自然语言数据,几乎所有非Unicode转换格式的编码都是过时的。如果没有Unicode,有些语言是你无法支持的。

答案 2 :(得分:3)

每当您读取应用程序外部的文件时,您应该使用默认编码,并且可以假定使用用户的本地编码,例如用户编写的文本文件。您可能希望在编写此类文件时使用默认编码,具体取决于用户稍后将对该文件执行的操作。

您应该对任何其他文件使用默认编码,尤其是与应用程序相关的文件。

如果您的应用程序以文本格式写配置文件,则应始终指定编码。一般来说,UTF-8总是一个不错的选择,因为它几乎与所有东西兼容。不这样做可能会导致其他国家/地区的用户意外崩溃。

这不仅限于字符编码,还包括日期/时间,数字或其他语言特定格式。例如,如果你在美国机器上使用默认编码和默认日期/时间字符串,然后尝试在德国服务器上读取该文件,你可能会惊讶为什么一半是胡言乱语而另一半有月/日混淆或关闭由于夏令时,一小时。

答案 3 :(得分:0)

当您使用PrintWriter时,

File file = new File(file_path);
Writer w = new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_16.name());
PrintWriter pw = new PrintWriter(w);
pw.println(content_to_write);
pw.close();
相关问题