Java编码转换问题详解:UTF-8、Unicode与GBK编码转换及中文乱码解决方案
文章目录

在 java 编码过程中,常常会遇到编码转换方面的问题,这些问题主要体现在 UTF-8 编码、unicode 编码与 GBK 编码之间的相互转换上。
主要原因经常需要转换,原因在于中文编码存在问题。若编解码不对应,就会经常遭遇令人烦躁的乱码情况。究其根本,在 unicode 系列编码和 GKB 系列编码中,同一个中文字符所对应的编码是不同的。
[id_448023804]
java源文件中中文字符的编码的问题
windows系统默认的编码为:gbk.
命令行编译 java 代码时,若不使用 -encoding 指定编码选项,就会默认以 GBK 编码进行编译。倘若源文件的编码并非 GBK 编码,那么编译时(有可能)会出现错误,即出现 xxx 编码不可映射的字符集这种情况。
linux/unix系统默认的编码为:utf-8.
命令行编译 java 代码时,如果不使用 -encoding 指定编码选项,就会默认以 utf-8 编码进行编译。倘若源文件的编码并非 utf-8 编码,那么在编译过程中(有可能)会出现错误,即出现 xxx 编码不可映射的字符集这种情况。
针对上述问题,在编译时指定与源文件相同的编码,这样输出的中文就能正常显示,也不会受到操作系统默认编码的影响。
在 Windows 系统下,使用 utf-8 编码的 Test.java 代码,借助下面的编译指令能够完成编译,并且中文在终端能够正常输出。
javac Test.java -encoding utf-8
java Test
UTF-8和GBK格式的文件相互转换
UTF-8 格式的数据不能直接转换为其他格式,需要先转化为 unicode 编码。GBK 格式的数据也不能直接转换为其他格式,同样需要先转化为 unicode 编码,然后才能进行转换。
unicode的码表官网:
unicode的编码范围和各国语言编码映射:
中文的编码在 unicode 码表中有所说明,其中涉及到 CJK(CJK 代表中文、日文、韩文三国文字)。关于 CJK 的相关说明。
ISO-8859-1向下兼容ASCII
特别说明:unicode 编码与 gbk 系列编码之间不存在确定的算数关联。若要进行准确的转换,就必须借助 unicode 码表以及中文字符编码的码表来实现转换。
一般情况下,在高级的编程语言里都会有提供 unicode 和 gbk 系列编码之间转换的 API。比如在 C/C++中,如果没有提供这样的功能,那么可以使用第三方库的 API 来进行转换,没有必要花费时间去自己重新开发。
java实现文件编码的转换
public static int convertFileEncoding(String srcFilePath,String srcCharset ,
String destFilePath,String destCharset,boolean isDeleteSrc) throws IOException {
if(srcFilePath == null || srcFilePath.length() == 0)
throw new IllegalArgumentException("srcFilePath is empty.");
if(destFilePath == null || destFilePath.length() == 0)
throw new IllegalArgumentException("destFilePath is empty.");
if(srcFilePath.equalsIgnoreCase(destFilePath))
throw new IllegalArgumentException(srcFilePath is equal to destFilePath. // 这一句是将原句进行了简单的同义替换,用“is equal to”替换了“is the same as”,保留了原意且避免了使用原文词语。);
if(srcCharset == null || srcCharset.length() == 0)
throw new IllegalArgumentException("srcCharset is empty.");
if(destCharset == null || destCharset.length() == 0)
throw new IllegalArgumentException("destCharset is empty.");
if(srcCharset.equalsIgnoreCase(destCharset)) // 编码相同,无需转换
return 0;
File srcFile = new File(srcFilePath);
FileInputStream fis = null;
InputStreamReader isr = null;
BufferedReader br = null;
FileOutputStream fos = null;
OutputStreamWriter osw = null;
try {
fis = new FileInputStream(srcFile);
isr = new InputStreamReader(fis, srcCharset);
BufferedReader 的 defaultCharBufferSize 为 8192。
// 即:8192 × 2 byte = 16k
如果是 utf-8 编码,中文占 3 个字节,用 16K 除以 3 可得 5461,也就是说只要每行的中文字符数量< 5461,读取的行数就是准确的,
否则,可能会截断一行,且可能会多写入 '\n',不过这种情况通常是不存在的。
如果源文件的最后一行不存在换行符,那么转码后的文件在最后会额外写入一个换行符。
br = new BufferedReader(isr);
以 UTF-8 格式将内容写入文件,该文件的绝对路径为 file.getAbsolutePath()。false 表示不追加,直接覆盖原有内容;true 表示追加文件。
fos = new FileOutputStream(destFilePath, false);
osw = new OutputStreamWriter(fos, destCharset);
String str = null;
// 创建StringBuffer字符串缓存区
StringBuffer sb = new StringBuffer();
int lines = 0;
// 通过readLine()方法遍历读取文件
while ((str = br.readLine()) != null) {