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

FindBugs报告错误:

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

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

public ArrayList getValuesFromFile(File file){ String line; StringTokenizer token; ArrayList list = null; BufferedReader br = null; try { br = new BufferedReader(new FileReader(file)); list = new ArrayList(); 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()? 我决定使用这种方法自动定义用户操作系统的字符集。

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

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

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

您必须意识到的是,如果您编写的文件类似于您在计算机上执行的操作,并且正在您正在另一台计算机上执行此操作(不具有相同的默认编码),则您不一定能够阅读你所写的内容。 使用特定的编码,进行写入和读取,如UTF8,确保文件始终相同,无论在编写文件时使用何种平台。

理想情况下,它应该是:

 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,您无法支持某些语言。

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

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

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

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

当您使用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();