Java字符编码原理Word格式.docx
《Java字符编码原理Word格式.docx》由会员分享,可在线阅读,更多相关《Java字符编码原理Word格式.docx(15页珍藏版)》请在冰豆网上搜索。
字号:
大中小
订阅
今天遇到一台服务器的默认编码是en_US又要使用文件存储中文,即需使用IO流时指定编码,研究了一下可如下使用:
读文件:
BufferedReader
从字符输入流中读取文本,缓冲各个字符,从而提供字符、数组和行的高效读取。
可以指定缓冲区的大小,或者可使用默认的大小。
大多数情况下,默认值就足够大了。
通常,Reader所作的每个读取请求都会导致对基础字符或字节流进行相应的读取请求。
因此,建议用BufferedReader包装所有其read()操作可能开销很高的Reader(如FileReader和InputStreamReader)。
例如,
BufferedReaderin
=newBufferedReader(newFileReader("
foo.in"
));
将缓冲指定文件的输入。
如果没有缓冲,则每次调用read()或readLine()都会导致从文件中读取字节,并将其转换为字符后返回,而这是极其低效的。
可以对使用DataInputStream进行按原文输入的程序进行本地化,方法是用合适的BufferedReader替换每个DataInputStream。
为了指定文件的编码方式,再进入如下修改:
//BufferedReaderin=newBufferedReader(newFileReader(saveFilename));
BufferedReaderin=newBufferedReader(newInputStreamReader(newFileInputStream(saveFilename),"
GB2312"
写文件:
BufferedWriter
将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。
可以指定缓冲区的大小,或者接受默认的大小。
在大多数情况下,默认值就足够大了。
该类提供了newLine()方法,它使用平台自己的行分隔符概念,此概念由系统属性line.separator定义。
并非所有平台都使用新行符('
\n'
)来终止各行。
因此调用此方法来终止每个输出行要优于直接写入新行符。
通常Writer将其输出立即发送到基础字符或字节流。
除非要求提示输出,否则建议用BufferedWriter包装所有其write()操作可能开销很高的Writer(如FileWriters和OutputStreamWriters)。
PrintWriterout
=newPrintWriter(newBufferedWriter(newFileWriter("
foo.out"
)));
将缓冲PrintWriter对文件的输出。
如果没有缓冲,则每次调用print()方法会导致将字符转换为字节,然后立即写入到文件,而这是极其低效的。
为了指定文件的编码方式:
PrintWriterout=newPrintWriter(newBufferedWriter(newOutputStreamWriter(newFileOutputStream(saveFilename),"
java的编码方式原理
java的JVM的缺省编码方式由系统的“本地语言环境”设置确定,和操作系统的类型无关。
在JAVA源文件-->
JAVAC-->
Class-->
Java-->
getBytes()-->
new
String()-->
显示的过程中,每一步都有编码的转换过程,这个过程总是存在的,只是有的时候用默认的参数进行
JAVAC是以系统默认编码读入源文件,然后按UNICODE进行编码的。
在JAVA运行的时候,JAVA也是采用UNICODE编码的,并且默认输入和输出的都是操作系统的默认编码,也就是说在new
String(bytes[,encode])中,系统认为输入的是编码为encode的字节流,换句话说,如果按encode来翻译bytes才能得到正确的结果,这个结果最后要在JAVA中保存,它还是要从这个encode转换成Unicode,也就是说有bytes-->
encode字符-->
Unicode字符的转换;
而在String.getBytes([encode])中,系统要做一个Unicode字符-->
bytes的转换。
以下是取得系统缺省编码方式
public
encoding
{
static
void
main(String[]
args)
Properties
initProp
=
new
Properties(System.getProperties());
System.out.println("
file.encoding:
"
+
initProp1.getPropert("
file.encoding"
user.language"
}
总之,java
编码都是Unicode
因此,
我们只要知道当前系统缺省的编码方式,然后Unicode编码转换成当前系统缺省的编码方式
JAVA字符编码之Unicode,ISO-8859,GBK,UTF-8编码及相互转换
1、函数介绍
在Java中,字符串用统一的Unicode编码,每个字符占用两个字节,与编码有关的两个主要函数为:
1)将字符串用指定的编码集合解析成字节数组,完成Unicode-〉charsetName转换
publicbyte[]getBytes(StringcharsetName)throwsUnsupportedEncodingException
2)将字节数组以指定的编码集合构造成字符串,完成charsetName-〉Unicode转换
publicString(byte[]bytes,StringcharsetName)throwsUnsupportedEncodingException
2、Unicode与各编码之间的直接转换
下面以对中文字符串"a中文"的编码转换为例,来了解各种编码之间的转换
1)Unicode和GBK
测试结果如下,每个汉字转换为两个字节,且是可逆的,即通过字节可以转换回字符串
String-GBK〉ByteArray:
\u0061\u4E2D\u6587(a中文)-〉0x610xD60xD00xCE0xC4
ByteArray-GBK〉String:
0x610xD60xD00xCE0xC4-〉\u0061\u4E2D\u6587(a中文)
2)Unicode和UTF-8
测试结果如下,每个汉字转换为三个字节,且是可逆的,即通过字节可以转换回字符串
String-UTF-8〉ByteArray:
\u0061\u4E2D\u6587(a中文)-〉0x610xE40xB80xAD0xE6%0x960x87
ByteArray-UTF-8〉String:
0x610xE40xB80xAD0xE6%0x960x87-〉\u0061\u4E2D\u6587(a中文)
3)Unicode和ISO-8859-1
测试结果如下,当存在汉字时转换失败,非可逆,即通过字节不能再转换回字符串
String-ISO-8859-1〉ByteArray:
\u0061\u4E2D\u6587(a中文)-〉0x610x3F0x3F
ByteArray-ISO-8859-1〉String:
0x610x3F0x3F-〉\u0061\u003F\u003F(a?
?
)
3、Unicode与各编码之间的交叉转换
在上面直接转换中,由字符串(Unicode)生成的字节数组,在构造回字符串时,使用的是正确的编码集合,如果使用的不是正确的编码集合会怎样呢?
会正确构造吗?
如果不能正确构造能有办法恢复吗?
会信息丢失吗?
下面我们就来看看这种情况,这部分可以说明在某些情况下虽然我们最终正确显示了结果,但其间仍然进行了不正确的转换。
1)能够正确显示的中间不正确转换
我们知道String-GBK〉ByteArray-GBK〉String是正确的,但如果我们采用String-GBK〉ByteArray-ISO-8859-1〉String呢?
通过测试结果如下:
String-GBK〉ByteArray-ISO-8859-1〉String:
\u0061\u4E2D\u6587(a中文)-〉0x610xD60xD00xCE0xC4-〉\u0061\u00D6\u00D0\u00CE\u00C4(a?
这时我们得到的字符串为?
乱码“a?
”,但是通过继续转换我们仍然可以复原回正确的字符串“a中文”,过程如下:
String-GBK〉ByteArray-ISO-8859-1〉String-ISO-8859-1〉ByteArray-GBK〉String
对应:
)-〉0x610xD60xD00xCE0xC4-〉\u0061\u4E2D\u6587(a中文)
也就是我们在首次构造字符串时,我们用了错误的编码集合得到了错误的乱码,但是我们通过错上加错,再用错误的编码集合获取字节数组,然后再用正确的编码集合构造,就又恢复了正确的字符串。
这时就属于是“能够正确显示的中间不正确转换”。
在Jsp页面提交数据处理时常常发生这种情况。
此外能够正确显示的中间不正确转换还有:
String-UTF-8〉ByteArray-ISO-8859-1〉String-ISO-8859-1〉ByteArray-UTF-8〉String
和
String-UTF-8〉ByteArray-GBK〉String-GBK〉ByteArray-UTF-8〉String
\u0061\u4E2D\u6587(a中文)-〉0x610xE40xB80xAD0xE6%0x960x87-〉\u0061\u6D93\uE15F\u6783(a涓枃)-〉0x610xE40xB80xAD0xE6%0x960x87-〉\u0061\u4E2D\u6587(a中文)
4、编码过程中错误诊断参考
1)一个汉字对应一个问号
在通过ISO-8859-1从字符串获取字节数组时,由于一个Unicode转换成一个byte,当遇到不认识的Unicode时,转换为0x3F,这样无论用哪种编码构造时都会产生一个?
乱码。
2)一个汉字对应两个问号
在通过GBK从字符串获取字节数组时,由于一个Unicode转换成两个byte,如果此时用ISO-8859-1或用UTF-8构造字符串就会出现两个问号。
若是通过ISO-8859-1构造可以再通过上面所说的错上加错恢复(即再通过从ISO-8859-1解析,用GBK构造);
若是通过UTF-8构造则会产生Unicode字符"\uFFFD",不能恢复,若再通过String-UTF-8〉ByteArray-GBK〉String,则会出现杂码,如a锟斤拷锟斤拷
3)一个汉字对应三个问号
在通过UTF-8从字符串获取字节数组时,由于一个Unicode转换成三个byte,如果此时用ISO-8859-1构造字符串就会出现三个问号;
用GBK构造字符串就会出现杂码,
java字符编码方式总结
2010-05-0115:
22
一、概要
在JAVA应用程序特别是基于WEB的程序中,经常遇到字符的编码问题。
为了防止出现乱码,首先需要了解JAVA是如何处理字符的,这样就可以有目的地在输入/输出环节中增加必要的转码。
其次,由于各种服务器有不同的处理方式,还需要多做试验,确保使用中不出现乱码。
二、基本概念
2.1JAVA中字符的表达
JAVA中有char、byte、String这几个概念。
char指的是一个UNICODE字符,为16位的整数。
byte是字节,字符串在网络传输或存储前需要转换为byte数组。
在从网络接收或从存储设备读取后需要将byte数组转换成String。
String是字符串,可以看成是由char组成的数组。
String和char为内存形式,byte是网络传输或存储的序列化形式。
举例:
英
Stringying=“英”;
charying=ying.charAt(0);
StringyingHex=Integer.toHexString(ying);
82F1
byteyingGBBytes=ying.getBytes(“GBK”);
GB编码的字节数值
D3A2
2.2编码方式的简介
String序列化成byte数组或反序列化时需要选择正确的编码方式。
如果编码方式不正确,就会得到一些0x3F的值。
常用的字符编码方式有ISO8859_1、GB2312、GBK、UTF-8/UTF-16/UTF-32。
ISO8859_1用来编码拉丁文,它由单字节(0-255)组成。
GB2312、GBK用来编码简体中文,它有单字节和双字节混合组成。
最高位为1的字节和下一个字节构成一个汉字,最高位为0的字节是ASCII码。
UTF-8/UTF-16/UTF-32是国际标准UNICODE的编码方式。
用得最多的是UTF-8,主要是因为它在对拉丁文编码时节约空间。
UNICODE值UTF-8编码
U-00000000-U-0000007F:
0xxxxxxx
U-00000080-U-000007FF:
110xxxxx10xxxxxx
U-00000800-U-0000FFFF:
1110xxxx10xxxxxx10xxxxxx
U-00010000-U-001FFFFF:
11110xxx10xxxxxx10xxxxxx10xxxxxx
U-00200000-U-03FFFFFF:
111110xx10xxxxxx10xxxxxx10xxxxxx10xxxxxx
U-04000000-U-7FFFFFFF:
1111110x10xxxxxx10xxxxxx10xxxxxx10xxxxxx10xxxxxx
三、J2SE中相关的函数
Stringstr=”英”;
//取得GB2312编码的字节
byte[]bytesGB2312=str.getBytes(“GB2312”);
//取得平台缺省编码的字节(solaris为ISO8859_1,windows为GB2312)
byte[]bytesDefault=str.getBytes();
//用指定的编码将字节转换成字符串
StringnewStrGB=newString(bytesGB2312,“GB2312”);
//用平台缺省的编码将字节转换成字符串(solaris为ISO8859_1,windows为GB2312)
StringnewStrDefault=newString(bytesDefault);
//用指定的编码从字节流里面读取字符
InputStreamin=xxx;
InputStreamReaderreader=InputStreamReader(in,“GB2312”);
charaChar=reader.read();
四、JSP、数据库的编码
4.1JSP中的编码
(1)静态声明:
CHARSET有两个作用:
JSP文件的编码方式:
在读取JSP文件、生成JAVA类时,源JSP文件中汉字的编码
JSP输出流的编码方式:
在执行JSP时,往response流里面写入数据的编码方式
(2)动态改变:
在往response流里面写数据前可以调用response.setContentType(),设定正确的编码类型。
(3)在TOMCAT中,由Request.getParameter()得到的参数,编码方式都是ISO8859_1。
所以如果在浏览器输入框内输入一个汉字“英”,在服务器端就得到一个ISO8859_1编码的(0x00,0xD3,0x00,0xA2)。
所以通常在接收参数时转码:
StringwrongStr=response.getParameter(“name”);
StringcorrectStr=newString(wrongStr.getBytes(“ISO8859_1”),”GB2312”);
在最新的SERVLET规范里面,也可以在获取参数之前执行如下代码:
request.setCharacterEncoding(“GB2312”);
4.2数据库的编码
(1)数据库使用UTF-16
如果String中是UNICODE字符,写入读出时不需要转码
(2)数据库使用ISO8859_1
如果String中是UNICODE字符,写入读出时需要转码
写入:
StringnewStr=newString(oldStr.getByte(“GB2312”),“ISO8859_1”);
读出:
StringnewStr=newString(oldStr.getByte(“ISO8859_1”),”GB2312”);
五、源文件的编码
5.1资源文件
资源文件的编码方式和编辑平台相关。
在WINDOWS平台下编写的资源文件,以GB2312方式编码。
在编译时需要转码,以确保在各个平台上的正确性:
native2ascii–encodingGB2312source.properties
这样从资源文件中读出的就是正确的UNICODE字符串。
5.2源文件
源文件的编码方式和编辑平台相关。
在WINDOWS平台下开发的源文件,以GB2312方式编码。
在编译的时候,需要指定源文件的编码方式:
javac–encodingGB2312
JAVA编译后生成的字节文件的编码为UTF-8。
①最新版TOMCAT4.1.18支持request.setCharacterEncoding(Stringenc)
②资源文件转码成company.name=\u82f1\u65af\u514b
③如果数据库使用utf-16则不需要这部分转码
④页面上应有
转码ⅰ:
Strings=newString
(request.getParameter(“name”).getBytes(“ISO8859_1”),”GB2312”);
转码ⅱ:
Strings=newString(name.getBytes(“GB2312”),”ISO8859_1”);
转码ⅲ:
Strings=newString(name.getBytes(“ISO8859_1”),”GB2312”);
一、关键技术点:
1、当前流行的字符编码格式有:
US-ASCII、ISO-8859-1、UTF-8、UTF-16BE、UTF-16LE、UTF-16、GBK、GB2312等,其中GBK、GB2312是专门处理中文编码的。
2、String的getBytes方法用于按指定编码获取字符串的字节数组,参数指定了解码格式,如果没有指定解码格式,则按系统默认编码格式。
3、String的“String(bytes[]bs,Stringcharset)”构造方法用于把字节数组按指定的格式组合成一个字符串对象
二、实例演示:
packagebook.String;
importjava.io.UnsupportedEncodingException;
/***//**
*转换字符串的编码
*@authorjoe
*
*/
public