java 中GBK 与UTF-8编码的转换
⽂章⽬录
java编码中常遇到的编码转换问题,主要是UTF-8、unicode与GBK编码之间的转换。
经常需要转换的主要原因是:中⽂编码的问题,如果编不对应,经常遇到令⼈烦躁的乱码问题。究其原因是:在unicode系列编码和GBK系列编码中,同⼀个中⽂的字符对应的编码不同。
在java中字符默认是编码的⽅式存储。
java 源⽂件中中⽂字符的编码的问题
windows系统默认的编码为:gbk.命令⾏编译java代码不⽤-encoding 指定编码选项时,会默认按照GBK编码编译,如果源⽂件编码不是GBK编码,编译(可能)将产⽣错误:xxx编码不可映射的字符集。
linux/unix系统默认的编码为:utf-8.命令⾏编译java代码不⽤-encoding 指定编码选项时,会默认按照utf-8编码编译,如果源⽂件编码不是utf-8编码,编译(可能)将产⽣错误:xxx编码不可映射的字符集。
针对以上问题,可在编译时指定和源⽂件⼀致的编码即可,输出中⽂将正常,将不受操作系统默认的编码的影响。
eg: windows下utf-8编码的Test.java代码,利⽤下⾯的编译指令可通过编译,且中⽂在终端输出正常。
UTF-8和GBK 格式的⽂件相互转换
UTF-8和GBK格式的数据不能直接转换,需要先转化为unicode编码,再进⾏转换。
unicode的码表官⽹:
unicode的编码范围和各国语⾔编码映射:
中⽂的编码在unicode码表中的CJK(CJK 是中⽂(Chinese)、⽇⽂(Japanese)、韩⽂(Korean)三国⽂字的缩写)中说明。。特别说明: unicode 和 gbk系列编码之间没有确定的算数关系,如果需要准确的转换,必须通过unicode码表和中⽂字符编码的码表进⾏转换。
⼀般情况下:⾼级的编程语⾔中都会提供 unicode 和 gbk系列编码之间转换的API,像C/C++中如果未提供,可以采⽤第三⽅库的API进⾏转换,没必要浪费时间,⾃⼰造轮⼦。
java 实现⽂件编码的转换javac Test .java -encoding utf -8java Test
1
2
3
4
5public  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 ))
1
2
3
4
5
6
7
8
throw  new  IllegalArgumentException ("srcFilePath is the same as destFilePath");  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格式写⼊⽂件,AbsolutePath()即该⽂件的绝对路径,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 ) {  // 使⽤readLine()⽅法⽆法进⾏换⾏,需要⼿动在原本输出的字符串后⾯加"\n"或"\r"  sb .append (str ).append ('\n');  osw .write (sb .toString ());  osw .flush ();      lines ++;  }    if (isDeleteSrc )  {  if (srcFile .delete ())    System .out .println (srcFile .getAbsolutePath () + " file is already deleted.");  else    System .out .println (srcFile .getAbsolutePath () + " file delete fail.");  }  //  System.out.println(lines);  return  lines ; } catch  (FileNotFoundException e ) {  // TODO Auto-generated catch block //  e.printStackTrace();  throw  e ; } catch  (UnsupportedEncodingException e ) {  // TODO Auto-generated catch block
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
java语言使用的字符码集是73
74
java 不同编码的字节数组的转换
定义class FileUtil实现  throw  e ; } catch  (IOException e ) {  // TODO: handle exception  throw  e ; } finally  {  // 与同⼀个⽂件关联的所有输出流(输⼊流),只需关闭⼀个即可  if  (null != fis )  try  {    fis .close ();    fis = null ;  } catch  (IOException e ) {    // TODO Auto-generated catch block    e .printStackTrace ();  }  if  (null != fos )  try  {    fos .close ();    fos = null ;  } catch  (IOException e ) {    // TODO Auto-generated catch block    e .printStackTrace ();  } }}
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99public  class  EncodingUtil { /**  * 将原正确编码的字符串src ,转化为编码为srcCharset 的字符串  *  * 前提是:确保原字符串的编码是⽆损(完整的). ⽆需知道原字符串的具体编码,  * 转化为⽬标编码的字符串由java 库⾃动实现,⽆需⾃⼰⼿动实现。  *  * 如果原编码字符串不能转化为⽬标编码,将会抛出UnsupportedEncodingException  *  * @param src  * @param srcCharset  * @param destCharet  * @return 转换后的字符串  * @throws UnsupportedEncodingException  */ public  static  String convertEncoding_Str (String src ,String srcCharset ,String destCharet )    throws  UnsupportedEncodingException {  byte [] bts = src .getBytes (destCharet );  return  new  String (bts , destCharet ); }  /**  * 将编码为srcCharset 的字节数组src 转化为编码为destCharet 的字节数组  *  * @param src  * @param srcCharset  * @param destCharet  * @return  * @throws UnsupportedEncodingException  */ public  static  byte []  convertEncoding_ByteArr (byte [] src ,String srcCharset ,String destCharet )
throws  UnsupportedEncodingException {
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
特别说明: java API中编码正确的字符串可通过String对象的 getBytes(String charset)获得不同编码的字节数组,但是通过字节数组构造字符串对象时,String(byte[],charset) 字节数组的原编码必须和构造字符串对象时指定的编码相同,否则可能构造的并⾮是预期的字符串。
测试程序: (操作系统为:ubuntu16.04)
throws  UnsupportedEncodingException {  String s = new  String (src , srcCharset );  return  s .getBytes (destCharet ); } /**  * 将字节数组byteArr 转化为2位16进制字符串,每个16进制之间⽤空格分割  *  * @param byteArr  * @return  */ public  static  String byteToHex (byte ... byteArr ) {  if  (null == byteArr || byteArr .length == 0)  return  "";  StringBuffer sb = new  StringBuffer ();  String tmp = null ;  for  (byte  b : byteArr ) {  tmp = Integer .toHexString (b );  // 切记:byte 进⾏运算时,会⾃动转化为int ,否则可能会出错  if  (b >>> 31 == 1) { // 最⾼位为1,负数    sb .append (tmp .substring (6));  } else  { // 最⾼位为0,正数    if (tmp .length () < 2)    sb .append ('0');    sb .append (tmp );  }  sb .append (' ');  }  sb .deleteCharAt (sb .length () - 1); // delete last space  return  sb .toString (); }}
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72import  java .io .IOException ;import  java .nio .charset .Charset ;public  class  Test {// ⼀// GB2312编码:D2BB BIG5编码:A440 GBK 编码:D2BB GB18030编码:D2BB Unicode 编码:4E00 ,utf-8: E4B880// 丁// GB2312编码:B6A1 BIG5编码:A442 GBK 编码:B6A1 GB18030编码:B6A1 Unicode 编码:4E01 ,utf-8: E4B881// 丂// GB2312编码:没有 BIG5编码:没有 GBK 编码:8140 GB18030编码:8140 Unicode 编码:4E02 ,utf-8: E4B882// 七// GB2312编码:C6DF BIG5编码:A443 GBK 编码:C6DF GB18030编码:C6DF Unicode 编码:4E03 ,utf-8: E4B883//  \r\n  : 0A 0D //  0-9 : 30 39//  A-Z : 41~5A  a-z : 61~7A
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
输出//  ⼀18丁a 丂七40// GBK      : D2BB 3138 B6A1 61 8140 C6DF 3430// unicode  : 4E00 3138 4E01 61 4E02 4E03 3430// utf-8    : E4B880 3138 E4B881 61 E4B882 E4B883 3430 public  static  void  main (String [] args ) throws  IOException {  System .out .println ("start");  String s = "⼀18丁a 丂七40";  System .out .println ("系统默认编码: " + System .getProperty ("ding"));// 查询结果GBK  // 系统默认字符编码  System .out .println ("系统默认字符编码:" + Charset .defaultCharset ()); // 查询结果GBK  // 操作系统⽤户使⽤的语⾔  System .out .println ("系统默认语⾔:" + System .getProperty ("user.language")); // 查询结果zh  // 使⽤系统默认的字符编码  byte [] defaultCharsetArr = s .getBytes ();  showByteArr (defaultCharsetArr ,"defaultCharsetArr");  // unicode 编码,在java 所有字符(中英⽂)均占2个字节  byte [] unicodeArr = s .getBytes ("unicode");  showByteArr (unicodeArr ,"unicodeArr");  // gbk 中⽂占2个字节,UTF-8k 中⽂占3个字节; 英⽂字符2者均占1个字节    byte [] gbkArr = s .getBytes ("gbk");  showByteArr (gbkArr ,"gbkArr");  byte [] utf8Arr = s .getBytes ("utf-8");  showByteArr (utf8Arr ,"utf8Arr");    // ISO-8859-1编码中不能出现中⽂,因为其将每个中⽂字符编码为1个字节(⾮法)  // 会造成字节的丢失  byte [] isoArr = s .getBytes ("ISO-8859-1");  showByteArr (isoArr ,"isoArr");    // gbk to utf-8  showByteArr (EncodingUtil .convertEncoding_ByteArr (gbkArr ,"gbk","utf-8"),"gbk to utf-8");  showByteArr (EncodingUtil .convert
Encoding_ByteArr (utf8Arr ,"utf-8","gbk"),"utf-8 to gbk");  showByteArr (EncodingUtil .convertEncoding_ByteArr (utf8Arr ,"utf-8","unicode"),"utf-8 to unicode");    System .out .println ("end"); }  private  static  void  showByteArr (byte [] arr ,String msg ) {  // TODO Auto-generated method stub  System .out .println (msg );  System .out .println ("byte[] len=:" + arr .length + "\n" + EncodingUtil .byteToHex (arr )); }}18192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。