java字符串的各种编码转换.docx
《java字符串的各种编码转换.docx》由会员分享,可在线阅读,更多相关《java字符串的各种编码转换.docx(9页珍藏版)》请在冰点文库上搜索。
java字符串的各种编码转换
importjava.io.UnsupportedEncodingException;
/**
*转换字符串的编码
*/
publicclassChangeCharset{
/**7位ASCII字符,也叫作ISO646-US、Unicode字符集的基本拉丁块*/
publicstaticfinalStringUS_ASCII="US-ASCII";
/**ISO拉丁字母表No.1,也叫作ISO-LATIN-1*/
publicstaticfinalStringISO_8859_1="ISO-8859-1";
/**8位UCS转换格式*/
publicstaticfinalStringUTF_8="UTF-8";
/**16位UCS转换格式,BigEndian(最低地址存放高位字节)字节顺序*/
publicstaticfinalStringUTF_16BE="UTF-16BE";
/**16位UCS转换格式,Little-endian(最高地址存放低位字节)字节顺序*/
publicstaticfinalStringUTF_16LE="UTF-16LE";
/**16位UCS转换格式,字节顺序由可选的字节顺序标记来标识*/
publicstaticfinalStringUTF_16="UTF-16";
/**中文超大字符集*/
publicstaticfinalStringGBK="GBK";
/**
*将字符编码转换成US-ASCII码
*/
publicStringtoASCII(Stringstr)throwsUnsupportedEncodingException{
returnthis.changeCharset(str,US_ASCII);
}
/**
*将字符编码转换成ISO-8859-1码
*/
publicStringtoISO_8859_1(Stringstr)throwsUnsupportedEncodingException{
returnthis.changeCharset(str,ISO_8859_1);
}
/**
*将字符编码转换成UTF-8码
*/
publicStringtoUTF_8(Stringstr)throwsUnsupportedEncodingException{
returnthis.changeCharset(str,UTF_8);
}
/**
*将字符编码转换成UTF-16BE码
*/
publicStringtoUTF_16BE(Stringstr)throwsUnsupportedEncodingException{
returnthis.changeCharset(str,UTF_16BE);
}
/**
*将字符编码转换成UTF-16LE码
*/
publicStringtoUTF_16LE(Stringstr)throwsUnsupportedEncodingException{
returnthis.changeCharset(str,UTF_16LE);
}
/**
*将字符编码转换成UTF-16码
*/
publicStringtoUTF_16(Stringstr)throwsUnsupportedEncodingException{
returnthis.changeCharset(str,UTF_16);
}
/**
*将字符编码转换成GBK码
*/
publicStringtoGBK(Stringstr)throwsUnsupportedEncodingException{
returnthis.changeCharset(str,GBK);
}
/**
*字符串编码转换的实现方法
*@paramstr待转换编码的字符串
*@paramnewCharset目标编码
*@return
*@throwsUnsupportedEncodingException
*/
publicStringchangeCharset(Stringstr,StringnewCharset)
throwsUnsupportedEncodingException{
if(str!
=null){
//用默认字符编码解码字符串。
byte[]bs=str.getBytes();
//用新的字符编码生成字符串
returnnewString(bs,newCharset);
}
returnnull;
}
/**
*字符串编码转换的实现方法
*@paramstr待转换编码的字符串
*@paramoldCharset原编码
*@paramnewCharset目标编码
*@return
*@throwsUnsupportedEncodingException
*/
publicStringchangeCharset(Stringstr,StringoldCharset,StringnewCharset)
throwsUnsupportedEncodingException{
if(str!
=null){
//用旧的字符编码解码字符串。
解码可能会出现异常。
byte[]bs=str.getBytes(oldCharset);
//用新的字符编码生成字符串
returnnewString(bs,newCharset);
}
returnnull;
}
publicstaticvoidmain(String[]args)throwsUnsupportedEncodingException{
ChangeCharsettest=newChangeCharset();
Stringstr="Thisisa中文的String!
";
System.out.println("str:
"+str);
Stringgbk=test.toGBK(str);
System.out.println("转换成GBK码:
"+gbk);
System.out.println();
Stringascii=test.toASCII(str);
System.out.println("转换成US-ASCII码:
"+ascii);
gbk=test.changeCharset(ascii,ChangeCharset.US_ASCII,ChangeCharset.GBK);
System.out.println("再把ASCII码的字符串转换成GBK码:
"+gbk);
System.out.println();
Stringiso88591=test.toISO_8859_1(str);
System.out.println("转换成ISO-8859-1码:
"+iso88591);
gbk=test.changeCharset(iso88591,ChangeCharset.ISO_8859_1,ChangeCharset.GBK);
System.out.println("再把ISO-8859-1码的字符串转换成GBK码:
"+gbk);
System.out.println();
Stringutf8=test.toUTF_8(str);
System.out.println("转换成UTF-8码:
"+utf8);
gbk=test.changeCharset(utf8,ChangeCharset.UTF_8,ChangeCharset.GBK);
System.out.println("再把UTF-8码的字符串转换成GBK码:
"+gbk);
System.out.println();
Stringutf16be=test.toUTF_16BE(str);
System.out.println("转换成UTF-16BE码:
"+utf16be);
gbk=test.changeCharset(utf16be,ChangeCharset.UTF_16BE,ChangeCharset.GBK);
System.out.println("再把UTF-16BE码的字符串转换成GBK码:
"+gbk);
System.out.println();
Stringutf16le=test.toUTF_16LE(str);
System.out.println("转换成UTF-16LE码:
"+utf16le);
gbk=test.changeCharset(utf16le,ChangeCharset.UTF_16LE,ChangeCharset.GBK);
System.out.println("再把UTF-16LE码的字符串转换成GBK码:
"+gbk);
System.out.println();
Stringutf16=test.toUTF_16(str);
System.out.println("转换成UTF-16码:
"+utf16);
gbk=test.changeCharset(utf16,ChangeCharset.UTF_16LE,ChangeCharset.GBK);
System.out.println("再把UTF-16码的字符串转换成GBK码:
"+gbk);
Strings=newString("中文".getBytes("UTF-8"),"UTF-8");
System.out.println(s);
}
}
------------------------------------------------------------------------------------------------------------------
java中的String类是按照unicode进行编码的,当使用String(byte[]bytes,Stringencoding)构造字符串时,encoding所指的是bytes中的数据是按照那种方式编码的,而不是最后产生的String是什么编码方式,换句话说,是让系统把bytes中的数据由encoding编码方式转换成unicode编码。
如果不指明,bytes的编码方式将由jdk根据操作系统决定。
当我们从文件中读数据时,最好使用InputStream方式,然后采用String(byte[]bytes,Stringencoding)指明文件的编码方式。
不要使用Reader方式,因为Reader方式会自动根据jdk指明的编码方式把文件内容转换成unicode编码。
当我们从数据库中读文本数据时,采用ResultSet.getBytes()方法取得字节数组,同样采用带编码方式的字符串构造方法即可。
ResultSetrs;
bytep[]bytes=rs.getBytes();
Stringstr=newString(bytes,"gb2312");
不要采取下面的步骤。
ResultSetrs;
Stringstr=rs.getString();
str=newString(str.getBytes("iso8859-1"),"gb2312");
这种编码转换方式效率底。
之所以这么做的原因是,ResultSet在getString()方法执行时,默认数据库里的数据编码方式为iso8859-1。
系统会把数据依照iso8859-1的编码方式转换成unicode。
使用str.getBytes("iso8859-1")把数据还原,然后利用newString(bytes,"gb2312")把数据从gb2312转换成unicode,中间多了好多步骤。
从HttpRequest中读参数时,利用reqeust.setCharacterEncoding()方法设置编码方式,读出的内容就是正确的了。
首先看一下下面的程序(测试英文和中文在Unicode、UTF-8、UTF-16这三种编码下,一个字符占几个字节)
System.out.println("a(Unicode):
"+"a".getBytes("Unicode").length);
System.out.println("a(Unicode):
"+"aa".getBytes("Unicode").length);
System.out.println("啊(Unicode):
"+"啊".getBytes("Unicode").length);
System.out.println("啊啊(Unicode):
"+"啊啊".getBytes("Unicode").length);
System.out.println("");
System.out.println("a(UTF-8):
"+"a".getBytes("UTF-8").length);
System.out.println("aa(UTF-8):
"+"aa".getBytes("UTF-8").length);
System.out.println("啊(UTF-8):
"+"啊".getBytes("UTF-8").length);
System.out.println("啊啊(UTF-8):
"+"啊啊".getBytes("UTF-8").length);
System.out.println("");
System.out.println("a(UTF-16):
"+"a".getBytes("UTF-16").length);
System.out.println("aa(UTF-16):
"+"aa".getBytes("UTF-16").length);
System.out.println("啊(UTF-16):
"+"啊".getBytes("UTF-16").length);
System.out.println("啊啊(UTF-16):
"+"啊啊".getBytes("UTF-16").length);
运行结果如下:
a(Unicode):
4
a(Unicode):
6
啊(Unicode):
4
啊啊(Unicode):
6
a(UTF-8):
1
aa(UTF-8):
2
啊(UTF-8):
3
啊啊(UTF-8):
6
a(UTF-16):
4
aa(UTF-16):
6
啊(UTF-16):
4
啊啊(UTF-16):
6
可以看到UTF-8的情况:
一个英文字符占一个字节,一个汉字占三个字节
但是Unicode和UTF-16的情况比较奇怪,不管是英文还是汉字,看不出占几个字节。
其实正确的答案是:
Unicode和UTF-16的编码下,不管是英文字符还是汉字字符,都占两个字节(至于上面结果中多出来的两个字节是用来表示字节顺序的默认字节)。
至于为什么,继续往下看。
Unicode规范中推荐的标记字节顺序的方法是BOM。
BOM不是“BillOfMaterial”的BOM表,而是ByteOrderMark。
(Unicode是一种字符编码方法,不过它是由国际组织设计,可以容纳全世界所有语言文字的编码方案。
Unicode的学名是"UniversalMultiple-OctetCodedCharacterSet",简称为UCS。
UCS可以看作是"UnicodeCharacterSet"的缩写。
)
在UCS编码中有一个叫做"ZEROWIDTHNO-BREAKSPACE"的字符,它的编码是FEFF。
而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。
UCS规范建议在传输字节流前,先传输字符"ZEROWIDTHNO-BREAKSPACE"。
这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little-Endian的。
因此字符"ZEROWIDTHNO-BREAKSPACE"又被称作BOM。
在Java中直接使用Unicode转码时会按照UTF-16LE的方式拆分,并加上BOM。
如果采用UTF-16拆分,在Java中默认采用带有BOM的UTF-16BE拆分。
再来看一个程序:
publicclassTest{
privatefinalstaticchar[]HEX="0123456789abcdef".toCharArray();
publicstaticvoidmain(String[]args)throwsUnsupportedEncodingException{
Stringstr="中国";
String[]encoding={"Unicode","UnicodeBig","UnicodeLittle","UnicodeBigUnmarked",
"UnicodeLittleUnmarked","UTF-16","UTF-16BE","UTF-16LE"};
for(inti=0;iSystem.out
.printf("%-22s%s%n",encoding[i],bytes2HexString(str.getBytes(encoding[i])));
}
}
publicstaticStringbytes2HexString(byte[]bys){
char[]chs=newchar[bys.length*2+bys.length-1];
for(inti=0,offset=0;iif(i>0){
chs[offset++]='';
}
chs[offset++]=HEX[bys[i]>>4&0xf];
chs[offset++]=HEX[bys[i]&0xf];
}
returnnewString(chs);
}
}
运行结果如下:
Unicodefeff4e2d56fd
UnicodeBigfeff4e2d56fd
UnicodeLittlefffe2d4efd56
UnicodeBigUnmarked4e2d56fd
UnicodeLittleUnmarked2d4efd56
UTF-16feff4e2d56fd
UTF-16BE4e2d56fd
UTF-16LE2d4efd56
可以看到几个不同的Unicode和UTF-16编码的字节顺序是不同的,有的是feff,有的是fffe,有的没有。
总上所述:
Unicode和UTF-16:
1个字符占2个字节(不管是哪国语言)
UTF-8:
1个英文字符占1个字节,一个汉字(包括日文和韩文等)占3个字节
Java中的char默认采用Unicode编码,所以Java中char占2个字节
另外,顺便提一个知识点:
1个字节(byte)占8位(bit)